1
/************************************************************************
4
(c) 1994, 1995 Innobase Oy
6
Created 6/9/1994 Heikki Tuuri
7
*************************************************************************/
15
#include "mach0data.h"
26
The basic element of the memory management is called a memory
27
heap. A memory heap is conceptually a
28
stack from which memory can be allocated. The stack may grow infinitely.
29
The top element of the stack may be freed, or
30
the whole stack can be freed at one time. The advantage of the
31
memory heap concept is that we can avoid using the malloc and free
32
functions of C which are quite expensive, for example, on the Solaris + GCC
33
system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
34
on Win NT + 100MHz Pentium, 2.5 microseconds.
35
When we use a memory heap,
36
we can allocate larger blocks of memory at a time and thus
37
reduce overhead. Slightly more efficient the method is when we
38
allocate the memory from the index page buffer pool, as we can
39
claim a new page fast. This is called buffer allocation.
40
When we allocate the memory from the dynamic memory of the
41
C environment, that is called dynamic allocation.
43
The default way of operation of the memory heap is the following.
44
First, when the heap is created, an initial block of memory is
45
allocated. In dynamic allocation this may be about 50 bytes.
46
If more space is needed, additional blocks are allocated
47
and they are put into a linked list.
48
After the initial block, each allocated block is twice the size of the
49
previous, until a threshold is attained, after which the sizes
50
of the blocks stay the same. An exception is, of course, the case
51
where the caller requests a memory buffer whose size is
52
bigger than the threshold. In that case a block big enough must
55
The heap is physically arranged so that if the current block
56
becomes full, a new block is allocated and always inserted in the
57
chain of blocks as the last block.
59
In the debug version of the memory management, all the allocated
60
heaps are kept in a list (which is implemented as a hash table).
61
Thus we can notice if the caller tries to free an already freed
62
heap. In addition, each buffer given to the caller contains
63
start field at the start and a trailer field at the end of the buffer.
65
The start field has the following content:
66
A. sizeof(ulint) bytes of field length (in the standard byte order)
67
B. sizeof(ulint) bytes of check field (a random number)
69
The trailer field contains:
70
A. sizeof(ulint) bytes of check field (the same random number as at the start)
72
Thus we can notice if something has been copied over the
73
borders of the buffer, which is illegal.
74
The memory in the buffers is initialized to a random byte sequence.
75
After freeing, all the blocks in the heap are set to random bytes
76
to help us discover errors which result from the use of
77
buffers in an already freed heap. */
79
#ifdef MEM_PERIODIC_CHECK
81
ibool mem_block_list_inited;
82
/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
83
UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
87
/*******************************************************************
88
NOTE: Use the corresponding macro instead of this function.
89
Allocates a single buffer of memory from the dynamic memory of
90
the C compiler. Is like malloc of C. The buffer must be freed
94
mem_alloc_func_noninline(
95
/*=====================*/
96
/* out, own: free storage */
97
ulint n, /* in: desired number of bytes */
98
const char* file_name, /* in: file name where created */
99
ulint line) /* in: line where created */
101
return(mem_alloc_func(n, file_name, line));
104
/**************************************************************************
105
Duplicates a NUL-terminated string, allocated from a memory heap. */
110
/* out, own: a copy of the string */
111
mem_heap_t* heap, /* in: memory heap where string is allocated */
112
const char* str) /* in: string to be copied */
114
return(mem_heap_dup(heap, str, strlen(str) + 1));
117
/**************************************************************************
118
Duplicate a block of data, allocated from a memory heap. */
123
/* out, own: a copy of the data */
124
mem_heap_t* heap, /* in: memory heap where copy is allocated */
125
const void* data, /* in: data to be copied */
126
ulint len) /* in: length of data, in bytes */
128
return(memcpy(mem_heap_alloc(heap, len), data, len));
131
/**************************************************************************
132
Concatenate two memory blocks and return the result, using a memory heap. */
137
/* out, own: the result */
138
mem_heap_t* heap, /* in: memory heap where result is allocated */
139
const void* b1, /* in: block 1 */
140
ulint len1, /* in: length of b1, in bytes */
141
const void* b2, /* in: block 2 */
142
ulint len2) /* in: length of b2, in bytes */
144
void* res = mem_heap_alloc(heap, len1 + len2);
146
memcpy(res, b1, len1);
147
memcpy((char*)res + len1, b2, len2);
152
/**************************************************************************
153
Concatenate two strings and return the result, using a memory heap. */
158
/* out, own: the result */
159
mem_heap_t* heap, /* in: memory heap where string is allocated */
160
const char* s1, /* in: string 1 */
161
const char* s2) /* in: string 2 */
164
ulint s1_len = strlen(s1);
165
ulint s2_len = strlen(s2);
167
s = mem_heap_alloc(heap, s1_len + s2_len + 1);
169
memcpy(s, s1, s1_len);
170
memcpy(s + s1_len, s2, s2_len);
172
s[s1_len + s2_len] = '\0';
178
/********************************************************************
179
Helper function for mem_heap_printf. */
184
/* out: length of formatted string,
185
including terminating NUL */
186
char* buf, /* in/out: buffer to store formatted string
187
in, or NULL to just calculate length */
188
const char* format, /* in: format string */
189
va_list ap) /* in: arguments */
195
/* Does this format specifier have the 'l' length modifier. */
196
ibool is_long = FALSE;
198
/* Length of one parameter. */
201
if (*format++ != '%') {
202
/* Non-format character. */
207
*buf++ = *(format - 1);
213
if (*format == 'l') {
222
char* s = va_arg(ap, char*);
224
/* "%ls" is a non-sensical format specifier. */
231
memcpy(buf, s, plen);
244
/* We only support 'long' values for now. */
247
val = va_arg(ap, unsigned long);
249
plen = sprintf(tmp, "%lu", val);
253
memcpy(buf, tmp, plen);
262
/* "%l%" is a non-sensical format specifier. */
278
/* For the NUL character. */
288
/********************************************************************
289
A simple (s)printf replacement that dynamically allocates the space for the
290
formatted string from the given heap. This supports a very limited set of
291
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
292
required for the 'u' type). */
297
/* out: heap-allocated formatted string */
298
mem_heap_t* heap, /* in: memory heap */
299
const char* format, /* in: format string */
306
/* Calculate length of string */
308
va_start(ap, format);
309
len = mem_heap_printf_low(NULL, format, ap);
312
/* Now create it for real. */
313
str = mem_heap_alloc(heap, len);
314
va_start(ap, format);
315
mem_heap_printf_low(str, format, ap);
321
/*******************************************************************
322
Creates a memory heap block where data can be allocated. */
325
mem_heap_create_block(
326
/*==================*/
327
/* out, own: memory heap block, NULL if
328
did not succeed (only possible for
329
MEM_HEAP_BTR_SEARCH type heaps) */
330
mem_heap_t* heap, /* in: memory heap or NULL if first block
332
ulint n, /* in: number of bytes needed for user data, or
333
if init_block is not NULL, its size in bytes */
334
void* init_block, /* in: init block in fast create,
335
type must be MEM_HEAP_DYNAMIC */
336
ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC or
338
const char* file_name,/* in: file name where created */
339
ulint line) /* in: line where created */
344
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
345
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
347
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
348
mem_analyze_corruption(heap);
351
/* In dynamic allocation, calculate the size: block header + data. */
353
if (init_block != NULL) {
354
ut_ad(type == MEM_HEAP_DYNAMIC);
355
ut_ad(n > MEM_BLOCK_START_SIZE + MEM_BLOCK_HEADER_SIZE);
359
} else if (type == MEM_HEAP_DYNAMIC) {
361
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
362
block = mem_area_alloc(len, mem_comm_pool);
364
ut_ad(n <= MEM_MAX_ALLOC_IN_BUF);
366
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
368
if (len < UNIV_PAGE_SIZE / 2) {
370
block = mem_area_alloc(len, mem_comm_pool);
372
len = UNIV_PAGE_SIZE;
374
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
375
/* We cannot allocate the block from the
376
buffer pool, but must get the free block from
377
the heap header free block field */
379
block = (mem_block_t*)heap->free_block;
380
heap->free_block = NULL;
382
block = (mem_block_t*)buf_frame_alloc();
388
/* Only MEM_HEAP_BTR_SEARCH allocation should ever fail. */
389
ut_a(type & MEM_HEAP_BTR_SEARCH);
394
block->magic_n = MEM_BLOCK_MAGIC_N;
395
ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
398
#ifdef MEM_PERIODIC_CHECK
399
mem_pool_mutex_enter();
401
if (!mem_block_list_inited) {
402
mem_block_list_inited = TRUE;
403
UT_LIST_INIT(mem_block_list);
406
UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
408
mem_pool_mutex_exit();
410
mem_block_set_len(block, len);
411
mem_block_set_type(block, type);
412
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
413
mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
415
block->free_block = NULL;
416
block->init_block = (init_block != NULL);
418
ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
423
/*******************************************************************
424
Adds a new block to a memory heap. */
429
/* out: created block, NULL if did not
430
succeed (only possible for
431
MEM_HEAP_BTR_SEARCH type heaps)*/
432
mem_heap_t* heap, /* in: memory heap */
433
ulint n) /* in: number of bytes user needs */
436
mem_block_t* new_block;
439
ut_ad(mem_heap_check(heap));
441
block = UT_LIST_GET_LAST(heap->base);
443
/* We have to allocate a new block. The size is always at least
444
doubled until the standard size is reached. After that the size
445
stays the same, except in cases where the caller needs more space. */
447
new_size = 2 * mem_block_get_len(block);
449
if (heap->type != MEM_HEAP_DYNAMIC) {
450
/* From the buffer pool we allocate buffer frames */
451
ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
453
if (new_size > MEM_MAX_ALLOC_IN_BUF) {
454
new_size = MEM_MAX_ALLOC_IN_BUF;
456
} else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
458
new_size = MEM_BLOCK_STANDARD_SIZE;
465
new_block = mem_heap_create_block(heap, new_size, NULL, heap->type,
466
heap->file_name, heap->line);
467
if (new_block == NULL) {
472
/* Add the new block as the last block */
474
UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
479
/**********************************************************************
480
Frees a block from a memory heap. */
485
mem_heap_t* heap, /* in: heap */
486
mem_block_t* block) /* in: block to free */
492
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
493
mem_analyze_corruption(block);
496
UT_LIST_REMOVE(list, heap->base, block);
498
#ifdef MEM_PERIODIC_CHECK
499
mem_pool_mutex_enter();
501
UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
503
mem_pool_mutex_exit();
507
init_block = block->init_block;
508
block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
510
#ifdef UNIV_MEM_DEBUG
511
/* In the debug version we set the memory to a random combination
512
of hex 0xDE and 0xAD. */
514
mem_erase_buf((byte*)block, len);
515
#else /* UNIV_MEM_DEBUG */
516
UNIV_MEM_ASSERT_AND_FREE(block, len);
517
#endif /* UNIV_MEM_DEBUG */
520
/* Do not have to free: do nothing */
522
} else if (type == MEM_HEAP_DYNAMIC) {
524
mem_area_free(block, mem_comm_pool);
526
ut_ad(type & MEM_HEAP_BUFFER);
528
if (len >= UNIV_PAGE_SIZE / 2) {
529
buf_frame_free((byte*)block);
531
mem_area_free(block, mem_comm_pool);
536
/**********************************************************************
537
Frees the free_block field from a memory heap. */
540
mem_heap_free_block_free(
541
/*=====================*/
542
mem_heap_t* heap) /* in: heap */
544
if (heap->free_block) {
546
buf_frame_free(heap->free_block);
548
heap->free_block = NULL;
552
#ifdef MEM_PERIODIC_CHECK
553
/**********************************************************************
554
Goes through the list of all allocated mem blocks, checks their magic
555
numbers, and reports possible corruption. */
558
mem_validate_all_blocks(void)
559
/*=========================*/
563
mem_pool_mutex_enter();
565
block = UT_LIST_GET_FIRST(mem_block_list);
568
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
569
mem_analyze_corruption(block);
572
block = UT_LIST_GET_NEXT(mem_block_list, block);
575
mem_pool_mutex_exit();