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
Duplicates a NUL-terminated string, allocated from a memory heap. */
93
/* out, own: a copy of the string */
94
mem_heap_t* heap, /* in: memory heap where string is allocated */
95
const char* str) /* in: string to be copied */
97
return(mem_heap_dup(heap, str, strlen(str) + 1));
100
/**************************************************************************
101
Duplicate a block of data, allocated from a memory heap. */
106
/* out, own: a copy of the data */
107
mem_heap_t* heap, /* in: memory heap where copy is allocated */
108
const void* data, /* in: data to be copied */
109
ulint len) /* in: length of data, in bytes */
111
return(memcpy(mem_heap_alloc(heap, len), data, len));
114
/**************************************************************************
115
Concatenate two memory blocks and return the result, using a memory heap. */
120
/* out, own: the result */
121
mem_heap_t* heap, /* in: memory heap where result is allocated */
122
const void* b1, /* in: block 1 */
123
ulint len1, /* in: length of b1, in bytes */
124
const void* b2, /* in: block 2 */
125
ulint len2) /* in: length of b2, in bytes */
127
void* res = mem_heap_alloc(heap, len1 + len2);
129
memcpy(res, b1, len1);
130
memcpy((char*)res + len1, b2, len2);
135
/**************************************************************************
136
Concatenate two strings and return the result, using a memory heap. */
141
/* out, own: the result */
142
mem_heap_t* heap, /* in: memory heap where string is allocated */
143
const char* s1, /* in: string 1 */
144
const char* s2) /* in: string 2 */
147
ulint s1_len = strlen(s1);
148
ulint s2_len = strlen(s2);
150
s = mem_heap_alloc(heap, s1_len + s2_len + 1);
152
memcpy(s, s1, s1_len);
153
memcpy(s + s1_len, s2, s2_len);
155
s[s1_len + s2_len] = '\0';
161
/********************************************************************
162
Helper function for mem_heap_printf. */
167
/* out: length of formatted string,
168
including terminating NUL */
169
char* buf, /* in/out: buffer to store formatted string
170
in, or NULL to just calculate length */
171
const char* format, /* in: format string */
172
va_list ap) /* in: arguments */
178
/* Does this format specifier have the 'l' length modifier. */
179
ibool is_long = FALSE;
181
/* Length of one parameter. */
184
if (*format++ != '%') {
185
/* Non-format character. */
190
*buf++ = *(format - 1);
196
if (*format == 'l') {
205
char* s = va_arg(ap, char*);
207
/* "%ls" is a non-sensical format specifier. */
214
memcpy(buf, s, plen);
227
/* We only support 'long' values for now. */
230
val = va_arg(ap, unsigned long);
232
plen = sprintf(tmp, "%lu", val);
236
memcpy(buf, tmp, plen);
245
/* "%l%" is a non-sensical format specifier. */
261
/* For the NUL character. */
271
/********************************************************************
272
A simple (s)printf replacement that dynamically allocates the space for the
273
formatted string from the given heap. This supports a very limited set of
274
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
275
required for the 'u' type). */
280
/* out: heap-allocated formatted string */
281
mem_heap_t* heap, /* in: memory heap */
282
const char* format, /* in: format string */
289
/* Calculate length of string */
291
va_start(ap, format);
292
len = mem_heap_printf_low(NULL, format, ap);
295
/* Now create it for real. */
296
str = mem_heap_alloc(heap, len);
297
va_start(ap, format);
298
mem_heap_printf_low(str, format, ap);
304
/*******************************************************************
305
Creates a memory heap block where data can be allocated. */
308
mem_heap_create_block(
309
/*==================*/
310
/* out, own: memory heap block, NULL if
311
did not succeed (only possible for
312
MEM_HEAP_BTR_SEARCH type heaps) */
313
mem_heap_t* heap, /* in: memory heap or NULL if first block
315
ulint n, /* in: number of bytes needed for user data */
316
ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC or
318
const char* file_name,/* in: file name where created */
319
ulint line) /* in: line where created */
321
buf_block_t* buf_block = NULL;
325
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
326
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
328
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
329
mem_analyze_corruption(heap);
332
/* In dynamic allocation, calculate the size: block header + data. */
334
if (type == MEM_HEAP_DYNAMIC) {
336
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
337
block = mem_area_alloc(&len, mem_comm_pool);
339
ut_ad(n <= MEM_MAX_ALLOC_IN_BUF);
341
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
343
if (len < UNIV_PAGE_SIZE / 2) {
345
block = mem_area_alloc(&len, mem_comm_pool);
347
len = UNIV_PAGE_SIZE;
349
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
350
/* We cannot allocate the block from the
351
buffer pool, but must get the free block from
352
the heap header free block field */
354
buf_block = heap->free_block;
355
heap->free_block = NULL;
357
if (UNIV_UNLIKELY(!buf_block)) {
362
buf_block = buf_block_alloc(0);
365
block = (mem_block_t*) buf_block->frame;
370
block->buf_block = buf_block;
371
block->magic_n = MEM_BLOCK_MAGIC_N;
372
ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
375
#ifdef MEM_PERIODIC_CHECK
376
mem_pool_mutex_enter();
378
if (!mem_block_list_inited) {
379
mem_block_list_inited = TRUE;
380
UT_LIST_INIT(mem_block_list);
383
UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
385
mem_pool_mutex_exit();
387
mem_block_set_len(block, len);
388
mem_block_set_type(block, type);
389
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
390
mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
392
block->free_block = NULL;
394
ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
399
/*******************************************************************
400
Adds a new block to a memory heap. */
405
/* out: created block, NULL if did not
406
succeed (only possible for
407
MEM_HEAP_BTR_SEARCH type heaps)*/
408
mem_heap_t* heap, /* in: memory heap */
409
ulint n) /* in: number of bytes user needs */
412
mem_block_t* new_block;
415
ut_ad(mem_heap_check(heap));
417
block = UT_LIST_GET_LAST(heap->base);
419
/* We have to allocate a new block. The size is always at least
420
doubled until the standard size is reached. After that the size
421
stays the same, except in cases where the caller needs more space. */
423
new_size = 2 * mem_block_get_len(block);
425
if (heap->type != MEM_HEAP_DYNAMIC) {
426
/* From the buffer pool we allocate buffer frames */
427
ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
429
if (new_size > MEM_MAX_ALLOC_IN_BUF) {
430
new_size = MEM_MAX_ALLOC_IN_BUF;
432
} else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
434
new_size = MEM_BLOCK_STANDARD_SIZE;
441
new_block = mem_heap_create_block(heap, new_size, heap->type,
442
heap->file_name, heap->line);
443
if (new_block == NULL) {
448
/* Add the new block as the last block */
450
UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
455
/**********************************************************************
456
Frees a block from a memory heap. */
461
mem_heap_t* heap, /* in: heap */
462
mem_block_t* block) /* in: block to free */
466
buf_block_t* buf_block;
468
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
469
mem_analyze_corruption(block);
472
UT_LIST_REMOVE(list, heap->base, block);
474
#ifdef MEM_PERIODIC_CHECK
475
mem_pool_mutex_enter();
477
UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
479
mem_pool_mutex_exit();
483
buf_block = block->buf_block;
484
block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
486
#ifdef UNIV_MEM_DEBUG
487
/* In the debug version we set the memory to a random combination
488
of hex 0xDE and 0xAD. */
490
mem_erase_buf((byte*)block, len);
491
#else /* UNIV_MEM_DEBUG */
492
UNIV_MEM_ASSERT_AND_FREE(block, len);
493
#endif /* UNIV_MEM_DEBUG */
495
if (type == MEM_HEAP_DYNAMIC) {
498
mem_area_free(block, mem_comm_pool);
500
ut_ad(type & MEM_HEAP_BUFFER);
502
if (len >= UNIV_PAGE_SIZE / 2) {
503
buf_block_free(buf_block);
506
mem_area_free(block, mem_comm_pool);
511
/**********************************************************************
512
Frees the free_block field from a memory heap. */
515
mem_heap_free_block_free(
516
/*=====================*/
517
mem_heap_t* heap) /* in: heap */
519
if (UNIV_LIKELY_NULL(heap->free_block)) {
521
buf_block_free(heap->free_block);
523
heap->free_block = NULL;
527
#ifdef MEM_PERIODIC_CHECK
528
/**********************************************************************
529
Goes through the list of all allocated mem blocks, checks their magic
530
numbers, and reports possible corruption. */
533
mem_validate_all_blocks(void)
534
/*=========================*/
538
mem_pool_mutex_enter();
540
block = UT_LIST_GET_FIRST(mem_block_list);
543
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
544
mem_analyze_corruption(block);
547
block = UT_LIST_GET_NEXT(mem_block_list, block);
550
mem_pool_mutex_exit();