~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/************************************************************************
2
The memory management
3
4
(c) 1994, 1995 Innobase Oy
5
6
Created 6/8/1994 Heikki Tuuri
7
*************************************************************************/
8
9
#include "mem0dbg.ic"
10
11
#include "mem0pool.h"
12
13
/*******************************************************************
14
Creates a memory heap block where data can be allocated. */
15
16
mem_block_t*
17
mem_heap_create_block(
18
/*==================*/
19
				/* out, own: memory heap block, NULL if
20
				did not succeed (only possible for
21
				MEM_HEAP_BTR_SEARCH type heaps) */
22
	mem_heap_t*	heap,	/* in: memory heap or NULL if first block
23
				should be created */
24
	ulint		n,	/* in: number of bytes needed for user data, or
25
				if init_block is not NULL, its size in bytes */
26
	void*		init_block, /* in: init block in fast create,
27
				type must be MEM_HEAP_DYNAMIC */
28
	ulint		type,	/* in: type of heap: MEM_HEAP_DYNAMIC or
29
				MEM_HEAP_BUFFER */
30
	const char*	file_name,/* in: file name where created */
31
	ulint		line);	/* in: line where created */
32
/**********************************************************************
33
Frees a block from a memory heap. */
34
35
void
36
mem_heap_block_free(
37
/*================*/
38
	mem_heap_t*	heap,	/* in: heap */
39
	mem_block_t*	block);	/* in: block to free */
40
/**********************************************************************
41
Frees the free_block field from a memory heap. */
42
43
void
44
mem_heap_free_block_free(
45
/*=====================*/
46
	mem_heap_t*	heap);	/* in: heap */
47
/*******************************************************************
48
Adds a new block to a memory heap. */
49
50
mem_block_t*
51
mem_heap_add_block(
52
/*===============*/
53
				/* out: created block, NULL if did not
54
				succeed (only possible for
55
				MEM_HEAP_BTR_SEARCH type heaps)*/
56
	mem_heap_t*	heap,	/* in: memory heap */
57
	ulint		n);	/* in: number of bytes user needs */
58
59
UNIV_INLINE
60
void
61
mem_block_set_len(mem_block_t* block, ulint len)
62
{
63
	ut_ad(len > 0);
64
65
	block->len = len;
66
}
67
68
UNIV_INLINE
69
ulint
70
mem_block_get_len(mem_block_t* block)
71
{
72
	return(block->len);
73
}
74
75
UNIV_INLINE
76
void
77
mem_block_set_type(mem_block_t* block, ulint type)
78
{
79
	ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
80
	      || (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
81
82
	block->type = type;
83
}
84
85
UNIV_INLINE
86
ulint
87
mem_block_get_type(mem_block_t* block)
88
{
89
	return(block->type);
90
}
91
92
UNIV_INLINE
93
void
94
mem_block_set_free(mem_block_t* block, ulint free)
95
{
96
	ut_ad(free > 0);
97
	ut_ad(free <= mem_block_get_len(block));
98
99
	block->free = free;
100
}
101
102
UNIV_INLINE
103
ulint
104
mem_block_get_free(mem_block_t* block)
105
{
106
	return(block->free);
107
}
108
109
UNIV_INLINE
110
void
111
mem_block_set_start(mem_block_t* block, ulint start)
112
{
113
	ut_ad(start > 0);
114
115
	block->start = start;
116
}
117
118
UNIV_INLINE
119
ulint
120
mem_block_get_start(mem_block_t* block)
121
{
122
	return(block->start);
123
}
124
125
/*******************************************************************
126
Allocates n bytes of memory from a memory heap. */
127
UNIV_INLINE
128
void*
129
mem_heap_alloc(
130
/*===========*/
131
				/* out: allocated storage, NULL if did not
132
				succeed (only possible for
133
				MEM_HEAP_BTR_SEARCH type heaps) */
134
	mem_heap_t*	heap,	/* in: memory heap */
135
	ulint		n)	/* in: number of bytes; if the heap is allowed
136
				to grow into the buffer pool, this must be
137
				<= MEM_MAX_ALLOC_IN_BUF */
138
{
139
	mem_block_t*	block;
140
	void*		buf;
141
	ulint		free;
142
143
	ut_ad(mem_heap_check(heap));
144
145
	block = UT_LIST_GET_LAST(heap->base);
146
147
	ut_ad(!(block->type & MEM_HEAP_BUFFER) || (n <= MEM_MAX_ALLOC_IN_BUF));
148
149
	/* Check if there is enough space in block. If not, create a new
150
	block to the heap */
151
152
	if (mem_block_get_len(block)
153
	    < mem_block_get_free(block) + MEM_SPACE_NEEDED(n)) {
154
155
		block = mem_heap_add_block(heap, n);
156
157
		if (block == NULL) {
158
159
			return(NULL);
160
		}
161
	}
162
163
	free = mem_block_get_free(block);
164
165
	buf = (byte*)block + free;
166
167
	mem_block_set_free(block, free + MEM_SPACE_NEEDED(n));
168
169
#ifdef UNIV_MEM_DEBUG
170
	UNIV_MEM_ALLOC(buf,
171
		       n + MEM_FIELD_HEADER_SIZE + MEM_FIELD_TRAILER_SIZE);
172
173
	/* In the debug version write debugging info to the field */
174
	mem_field_init((byte*)buf, n);
175
176
	/* Advance buf to point at the storage which will be given to the
177
	caller */
178
	buf = (byte*)buf + MEM_FIELD_HEADER_SIZE;
179
180
#endif
181
#ifdef UNIV_SET_MEM_TO_ZERO
182
	UNIV_MEM_ALLOC(buf, n);
183
	memset(buf, '\0', n);
184
#endif
185
	UNIV_MEM_ALLOC(buf, n);
186
	return(buf);
187
}
188
189
/*********************************************************************
190
Returns a pointer to the heap top. */
191
UNIV_INLINE
192
byte*
193
mem_heap_get_heap_top(
194
/*==================*/
195
				/* out: pointer to the heap top */
196
	mem_heap_t*	heap)	/* in: memory heap */
197
{
198
	mem_block_t*	block;
199
	byte*		buf;
200
201
	ut_ad(mem_heap_check(heap));
202
203
	block = UT_LIST_GET_LAST(heap->base);
204
205
	buf = (byte*)block + mem_block_get_free(block);
206
207
	return(buf);
208
}
209
210
/*********************************************************************
211
Frees the space in a memory heap exceeding the pointer given. The
212
pointer must have been acquired from mem_heap_get_heap_top. The first
213
memory block of the heap is not freed. */
214
UNIV_INLINE
215
void
216
mem_heap_free_heap_top(
217
/*===================*/
218
	mem_heap_t*	heap,	/* in: heap from which to free */
219
	byte*		old_top)/* in: pointer to old top of heap */
220
{
221
	mem_block_t*	block;
222
	mem_block_t*	prev_block;
223
#ifdef UNIV_MEM_DEBUG
224
	ibool		error;
225
	ulint		total_size;
226
	ulint		size;
227
#endif
228
229
	ut_ad(mem_heap_check(heap));
230
231
#ifdef UNIV_MEM_DEBUG
232
233
	/* Validate the heap and get its total allocated size */
234
	mem_heap_validate_or_print(heap, NULL, FALSE, &error, &total_size,
235
				   NULL, NULL);
236
	ut_a(!error);
237
238
	/* Get the size below top pointer */
239
	mem_heap_validate_or_print(heap, old_top, FALSE, &error, &size, NULL,
240
				   NULL);
241
	ut_a(!error);
242
243
#endif
244
245
	block = UT_LIST_GET_LAST(heap->base);
246
247
	while (block != NULL) {
248
		if (((byte*)block + mem_block_get_free(block) >= old_top)
249
		    && ((byte*)block <= old_top)) {
250
			/* Found the right block */
251
252
			break;
253
		}
254
255
		/* Store prev_block value before freeing the current block
256
		(the current block will be erased in freeing) */
257
258
		prev_block = UT_LIST_GET_PREV(list, block);
259
260
		mem_heap_block_free(heap, block);
261
262
		block = prev_block;
263
	}
264
265
	ut_ad(block);
266
267
	/* Set the free field of block */
268
	mem_block_set_free(block, old_top - (byte*)block);
269
270
#ifdef UNIV_MEM_DEBUG
271
	ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
272
273
	/* In the debug version erase block from top up */
274
	mem_erase_buf(old_top, (byte*)block + block->len - old_top);
275
276
	/* Update allocated memory count */
277
	mutex_enter(&mem_hash_mutex);
278
	mem_current_allocated_memory -= (total_size - size);
279
	mutex_exit(&mem_hash_mutex);
280
#else /* UNIV_MEM_DEBUG */
281
	UNIV_MEM_ASSERT_W(old_top, (byte*)block + block->len - old_top);
282
#endif /* UNIV_MEM_DEBUG */
283
	UNIV_MEM_ALLOC(old_top, (byte*)block + block->len - old_top);
284
285
	/* If free == start, we may free the block if it is not the first
286
	one */
287
288
	if ((heap != block) && (mem_block_get_free(block)
289
				== mem_block_get_start(block))) {
290
		mem_heap_block_free(heap, block);
291
	}
292
}
293
294
/*********************************************************************
295
Empties a memory heap. The first memory block of the heap is not freed. */
296
UNIV_INLINE
297
void
298
mem_heap_empty(
299
/*===========*/
300
	mem_heap_t*	heap)	/* in: heap to empty */
301
{
302
	mem_heap_free_heap_top(heap, (byte*)heap + mem_block_get_start(heap));
303
304
	if (heap->free_block) {
305
		mem_heap_free_block_free(heap);
306
	}
307
}
308
309
/*********************************************************************
310
Returns a pointer to the topmost element in a memory heap. The size of the
311
element must be given. */
312
UNIV_INLINE
313
void*
314
mem_heap_get_top(
315
/*=============*/
316
				/* out: pointer to the topmost element */
317
	mem_heap_t*	heap,	/* in: memory heap */
318
	ulint		n)	/* in: size of the topmost element */
319
{
320
	mem_block_t*	block;
321
	void*		buf;
322
323
	ut_ad(mem_heap_check(heap));
324
325
	block = UT_LIST_GET_LAST(heap->base);
326
327
	buf = (byte*)block + mem_block_get_free(block) - MEM_SPACE_NEEDED(n);
328
329
#ifdef UNIV_MEM_DEBUG
330
	ut_ad(mem_block_get_start(block) <=(ulint)((byte*)buf - (byte*)block));
331
332
	/* In the debug version, advance buf to point at the storage which
333
	was given to the caller in the allocation*/
334
335
	buf = (byte*)buf + MEM_FIELD_HEADER_SIZE;
336
337
	/* Check that the field lengths agree */
338
	ut_ad(n == (ulint)mem_field_header_get_len(buf));
339
#endif
340
341
	return(buf);
342
}
343
344
/*********************************************************************
345
Frees the topmost element in a memory heap. The size of the element must be
346
given. */
347
UNIV_INLINE
348
void
349
mem_heap_free_top(
350
/*==============*/
351
	mem_heap_t*	heap,	/* in: memory heap */
352
	ulint		n)	/* in: size of the topmost element */
353
{
354
	mem_block_t*	block;
355
356
	ut_ad(mem_heap_check(heap));
357
358
	block = UT_LIST_GET_LAST(heap->base);
359
360
	/* Subtract the free field of block */
361
	mem_block_set_free(block, mem_block_get_free(block)
362
			   - MEM_SPACE_NEEDED(n));
363
	UNIV_MEM_ASSERT_W((byte*) block + mem_block_get_free(block), n);
364
#ifdef UNIV_MEM_DEBUG
365
366
	ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
367
368
	/* In the debug version check the consistency, and erase field */
369
	mem_field_erase((byte*)block + mem_block_get_free(block), n);
370
#endif
371
372
	/* If free == start, we may free the block if it is not the first
373
	one */
374
375
	if ((heap != block) && (mem_block_get_free(block)
376
				== mem_block_get_start(block))) {
377
		mem_heap_block_free(heap, block);
378
	} else {
379
		/* Avoid a bogus UNIV_MEM_ASSERT_W() warning in a
380
		subsequent invocation of mem_heap_free_top().
381
		Originally, this was UNIV_MEM_FREE(), to catch writes
382
		to freed memory. */
383
		UNIV_MEM_ALLOC((byte*) block + mem_block_get_free(block), n);
384
	}
385
}
386
387
/*********************************************************************
388
NOTE: Use the corresponding macros instead of this function. Creates a
389
memory heap. For debugging purposes, takes also the file name and line as
390
argument. */
391
UNIV_INLINE
392
mem_heap_t*
393
mem_heap_create_func(
394
/*=================*/
395
					/* out, own: memory heap, NULL if
396
					did not succeed (only possible for
397
					MEM_HEAP_BTR_SEARCH type heaps)*/
398
	ulint		n,		/* in: desired start block size,
399
					this means that a single user buffer
400
					of size n will fit in the block,
401
					0 creates a default size block;
402
					if init_block is not NULL, n tells
403
					its size in bytes */
404
	void*		init_block,	/* in: if very fast creation is
405
					wanted, the caller can reserve some
406
					memory from its stack, for example,
407
					and pass it as the the initial block
408
					to the heap: then no OS call of malloc
409
					is needed at the creation. CAUTION:
410
					the caller must make sure the initial
411
					block is not unintentionally erased
412
					(if allocated in the stack), before
413
					the memory heap is explicitly freed. */
414
	ulint		type,		/* in: heap type */
415
	const char*	file_name,	/* in: file name where created */
416
	ulint		line)		/* in: line where created */
417
{
418
	mem_block_t*   block;
419
420
	if (n > 0) {
421
		block = mem_heap_create_block(NULL, n, init_block, type,
422
					      file_name, line);
423
	} else {
424
		block = mem_heap_create_block(NULL, MEM_BLOCK_START_SIZE,
425
					      init_block, type,
426
					      file_name, line);
427
	}
428
429
	if (block == NULL) {
430
431
		return(NULL);
432
	}
433
434
	UT_LIST_INIT(block->base);
435
436
	/* Add the created block itself as the first block in the list */
437
	UT_LIST_ADD_FIRST(list, block->base, block);
438
439
#ifdef UNIV_MEM_DEBUG
440
441
	mem_hash_insert(block, file_name, line);
442
443
#endif
444
445
	return(block);
446
}
447
448
/*********************************************************************
449
NOTE: Use the corresponding macro instead of this function. Frees the space
450
occupied by a memory heap. In the debug version erases the heap memory
451
blocks. */
452
UNIV_INLINE
453
void
454
mem_heap_free_func(
455
/*===============*/
456
	mem_heap_t*	heap,		/* in, own: heap to be freed */
457
	const char*	file_name __attribute__((unused)),
458
					/* in: file name where freed */
459
	ulint		line  __attribute__((unused)))
460
{
461
	mem_block_t*	block;
462
	mem_block_t*	prev_block;
463
464
	ut_ad(mem_heap_check(heap));
465
466
	block = UT_LIST_GET_LAST(heap->base);
467
468
#ifdef UNIV_MEM_DEBUG
469
470
	/* In the debug version remove the heap from the hash table of heaps
471
	and check its consistency */
472
473
	mem_hash_remove(heap, file_name, line);
474
475
#endif
476
477
	if (heap->free_block) {
478
		mem_heap_free_block_free(heap);
479
	}
480
481
	while (block != NULL) {
482
		/* Store the contents of info before freeing current block
483
		(it is erased in freeing) */
484
485
		prev_block = UT_LIST_GET_PREV(list, block);
486
487
		mem_heap_block_free(heap, block);
488
489
		block = prev_block;
490
	}
491
}
492
493
/*******************************************************************
494
NOTE: Use the corresponding macro instead of this function.
495
Allocates a single buffer of memory from the dynamic memory of
496
the C compiler. Is like malloc of C. The buffer must be freed
497
with mem_free. */
498
UNIV_INLINE
499
void*
500
mem_alloc_func(
501
/*===========*/
502
					/* out, own: free storage */
503
	ulint		n,		/* in: desired number of bytes */
504
	const char*	file_name,	/* in: file name where created */
505
	ulint		line		/* in: line where created */
506
	)
507
{
508
	mem_heap_t*	heap;
509
	void*		buf;
510
511
	heap = mem_heap_create_func(n, NULL, MEM_HEAP_DYNAMIC, file_name,
512
				    line);
513
514
	/* Note that as we created the first block in the heap big enough
515
	for the buffer requested by the caller, the buffer will be in the
516
	first block and thus we can calculate the pointer to the heap from
517
	the pointer to the buffer when we free the memory buffer. */
518
519
	buf = mem_heap_alloc(heap, n);
520
521
	ut_a((byte*)heap == (byte*)buf - MEM_BLOCK_HEADER_SIZE
522
	     - MEM_FIELD_HEADER_SIZE);
523
	return(buf);
524
}
525
526
/*******************************************************************
527
NOTE: Use the corresponding macro instead of this function. Frees a single
528
buffer of storage from the dynamic memory of the C compiler. Similar to the
529
free of C. */
530
UNIV_INLINE
531
void
532
mem_free_func(
533
/*==========*/
534
	void*		ptr,		/* in, own: buffer to be freed */
535
	const char*	file_name,	/* in: file name where created */
536
	ulint		line		/* in: line where created */
537
	)
538
{
539
	mem_heap_t*   heap;
540
541
	heap = (mem_heap_t*)((byte*)ptr - MEM_BLOCK_HEADER_SIZE
542
			     - MEM_FIELD_HEADER_SIZE);
543
	mem_heap_free_func(heap, file_name, line);
544
}
545
546
/*********************************************************************
547
Returns the space in bytes occupied by a memory heap. */
548
UNIV_INLINE
549
ulint
550
mem_heap_get_size(
551
/*==============*/
552
	mem_heap_t*	heap)	/* in: heap */
553
{
554
	mem_block_t*	block;
555
	ulint		size	= 0;
556
557
	ut_ad(mem_heap_check(heap));
558
559
	block = heap;
560
561
	while (block != NULL) {
562
563
		size += mem_block_get_len(block);
564
		block = UT_LIST_GET_NEXT(list, block);
565
	}
566
567
	if (heap->free_block) {
568
		size += UNIV_PAGE_SIZE;
569
	}
570
571
	return(size);
572
}
573
574
/**************************************************************************
575
Duplicates a NUL-terminated string. */
576
UNIV_INLINE
577
char*
578
mem_strdup(
579
/*=======*/
580
				/* out, own: a copy of the string,
581
				must be deallocated with mem_free */
582
	const char*	str)	/* in: string to be copied */
583
{
584
	ulint	len = strlen(str) + 1;
585
	return(memcpy(mem_alloc(len), str, len));
586
}
587
588
/**************************************************************************
589
Makes a NUL-terminated copy of a nonterminated string. */
590
UNIV_INLINE
591
char*
592
mem_strdupl(
593
/*========*/
594
				/* out, own: a copy of the string,
595
				must be deallocated with mem_free */
596
	const char*	str,	/* in: string to be copied */
597
	ulint		len)	/* in: length of str, in bytes */
598
{
599
	char*	s = mem_alloc(len + 1);
600
	s[len] = 0;
601
	return(memcpy(s, str, len));
602
}
603
604
/**************************************************************************
605
Makes a NUL-terminated copy of a nonterminated string,
606
allocated from a memory heap. */
607
UNIV_INLINE
608
char*
609
mem_heap_strdupl(
610
/*=============*/
611
				/* out, own: a copy of the string */
612
	mem_heap_t*	heap,	/* in: memory heap where string is allocated */
613
	const char*	str,	/* in: string to be copied */
614
	ulint		len)	/* in: length of str, in bytes */
615
{
616
	char*	s = mem_heap_alloc(heap, len + 1);
617
	s[len] = 0;
618
	return(memcpy(s, str, len));
619
}