1
/*****************************************************************************
3
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/************************************************************************
22
Created 6/9/1994 Heikki Tuuri
23
*************************************************************************/
39
The basic element of the memory management is called a memory
40
heap. A memory heap is conceptually a
41
stack from which memory can be allocated. The stack may grow infinitely.
42
The top element of the stack may be freed, or
43
the whole stack can be freed at one time. The advantage of the
44
memory heap concept is that we can avoid using the malloc and free
45
functions of C which are quite expensive, for example, on the Solaris + GCC
46
system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
47
on Win NT + 100MHz Pentium, 2.5 microseconds.
48
When we use a memory heap,
49
we can allocate larger blocks of memory at a time and thus
50
reduce overhead. Slightly more efficient the method is when we
51
allocate the memory from the index page buffer pool, as we can
52
claim a new page fast. This is called buffer allocation.
53
When we allocate the memory from the dynamic memory of the
54
C environment, that is called dynamic allocation.
56
The default way of operation of the memory heap is the following.
57
First, when the heap is created, an initial block of memory is
58
allocated. In dynamic allocation this may be about 50 bytes.
59
If more space is needed, additional blocks are allocated
60
and they are put into a linked list.
61
After the initial block, each allocated block is twice the size of the
62
previous, until a threshold is attained, after which the sizes
63
of the blocks stay the same. An exception is, of course, the case
64
where the caller requests a memory buffer whose size is
65
bigger than the threshold. In that case a block big enough must
68
The heap is physically arranged so that if the current block
69
becomes full, a new block is allocated and always inserted in the
70
chain of blocks as the last block.
72
In the debug version of the memory management, all the allocated
73
heaps are kept in a list (which is implemented as a hash table).
74
Thus we can notice if the caller tries to free an already freed
75
heap. In addition, each buffer given to the caller contains
76
start field at the start and a trailer field at the end of the buffer.
78
The start field has the following content:
79
A. sizeof(ulint) bytes of field length (in the standard byte order)
80
B. sizeof(ulint) bytes of check field (a random number)
82
The trailer field contains:
83
A. sizeof(ulint) bytes of check field (the same random number as at the start)
85
Thus we can notice if something has been copied over the
86
borders of the buffer, which is illegal.
87
The memory in the buffers is initialized to a random byte sequence.
88
After freeing, all the blocks in the heap are set to random bytes
89
to help us discover errors which result from the use of
90
buffers in an already freed heap. */
92
#ifdef MEM_PERIODIC_CHECK
94
ibool mem_block_list_inited;
95
/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
96
UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
100
/**************************************************************************
101
Duplicates a NUL-terminated string, allocated from a memory heap. */
106
/* out, own: a copy of the string */
107
mem_heap_t* heap, /* in: memory heap where string is allocated */
108
const char* str) /* in: string to be copied */
110
return(mem_heap_dup(heap, str, strlen(str) + 1));
113
/**************************************************************************
114
Duplicate a block of data, allocated from a memory heap. */
119
/* out, own: a copy of the data */
120
mem_heap_t* heap, /* in: memory heap where copy is allocated */
121
const void* data, /* in: data to be copied */
122
ulint len) /* in: length of data, in bytes */
124
return(memcpy(mem_heap_alloc(heap, len), data, len));
127
/**************************************************************************
128
Concatenate two memory blocks and return the result, using a memory heap. */
133
/* out, own: the result */
134
mem_heap_t* heap, /* in: memory heap where result is allocated */
135
const void* b1, /* in: block 1 */
136
ulint len1, /* in: length of b1, in bytes */
137
const void* b2, /* in: block 2 */
138
ulint len2) /* in: length of b2, in bytes */
140
void* res = mem_heap_alloc(heap, len1 + len2);
142
memcpy(res, b1, len1);
143
memcpy((char*)res + len1, b2, len2);
148
/**************************************************************************
149
Concatenate two strings and return the result, using a memory heap. */
154
/* out, own: the result */
155
mem_heap_t* heap, /* in: memory heap where string is allocated */
156
const char* s1, /* in: string 1 */
157
const char* s2) /* in: string 2 */
160
ulint s1_len = strlen(s1);
161
ulint s2_len = strlen(s2);
163
s = mem_heap_alloc(heap, s1_len + s2_len + 1);
165
memcpy(s, s1, s1_len);
166
memcpy(s + s1_len, s2, s2_len);
168
s[s1_len + s2_len] = '\0';
174
/********************************************************************
175
Helper function for mem_heap_printf. */
180
/* out: length of formatted string,
181
including terminating NUL */
182
char* buf, /* in/out: buffer to store formatted string
183
in, or NULL to just calculate length */
184
const char* format, /* in: format string */
185
va_list ap) /* in: arguments */
191
/* Does this format specifier have the 'l' length modifier. */
192
ibool is_long = FALSE;
194
/* Length of one parameter. */
197
if (*format++ != '%') {
198
/* Non-format character. */
203
*buf++ = *(format - 1);
209
if (*format == 'l') {
218
char* s = va_arg(ap, char*);
220
/* "%ls" is a non-sensical format specifier. */
227
memcpy(buf, s, plen);
240
/* We only support 'long' values for now. */
243
val = va_arg(ap, unsigned long);
245
plen = sprintf(tmp, "%lu", val);
249
memcpy(buf, tmp, plen);
258
/* "%l%" is a non-sensical format specifier. */
274
/* For the NUL character. */
284
/********************************************************************
285
A simple (s)printf replacement that dynamically allocates the space for the
286
formatted string from the given heap. This supports a very limited set of
287
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
288
required for the 'u' type). */
293
/* out: heap-allocated formatted string */
294
mem_heap_t* heap, /* in: memory heap */
295
const char* format, /* in: format string */
302
/* Calculate length of string */
304
va_start(ap, format);
305
len = mem_heap_printf_low(NULL, format, ap);
308
/* Now create it for real. */
309
str = mem_heap_alloc(heap, len);
310
va_start(ap, format);
311
mem_heap_printf_low(str, format, ap);
317
/*******************************************************************
318
Creates a memory heap block where data can be allocated. */
321
mem_heap_create_block(
322
/*==================*/
323
/* out, own: memory heap block, NULL if
324
did not succeed (only possible for
325
MEM_HEAP_BTR_SEARCH type heaps) */
326
mem_heap_t* heap, /* in: memory heap or NULL if first block
328
ulint n, /* in: number of bytes needed for user data */
329
ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC or
331
const char* file_name,/* in: file name where created */
332
ulint line) /* in: line where created */
334
buf_block_t* buf_block = NULL;
338
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
339
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
341
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
342
mem_analyze_corruption(heap);
345
/* In dynamic allocation, calculate the size: block header + data. */
346
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
348
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
350
ut_ad(type == MEM_HEAP_DYNAMIC || n <= MEM_MAX_ALLOC_IN_BUF);
352
block = mem_area_alloc(&len, mem_comm_pool);
354
len = UNIV_PAGE_SIZE;
356
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
357
/* We cannot allocate the block from the
358
buffer pool, but must get the free block from
359
the heap header free block field */
361
buf_block = heap->free_block;
362
heap->free_block = NULL;
364
if (UNIV_UNLIKELY(!buf_block)) {
369
buf_block = buf_block_alloc(0);
372
block = (mem_block_t*) buf_block->frame;
376
block->buf_block = buf_block;
377
block->magic_n = MEM_BLOCK_MAGIC_N;
378
ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
381
#ifdef MEM_PERIODIC_CHECK
382
mem_pool_mutex_enter();
384
if (!mem_block_list_inited) {
385
mem_block_list_inited = TRUE;
386
UT_LIST_INIT(mem_block_list);
389
UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
391
mem_pool_mutex_exit();
393
mem_block_set_len(block, len);
394
mem_block_set_type(block, type);
395
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
396
mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
398
block->free_block = NULL;
400
ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
405
/*******************************************************************
406
Adds a new block to a memory heap. */
411
/* out: created block, NULL if did not
412
succeed (only possible for
413
MEM_HEAP_BTR_SEARCH type heaps)*/
414
mem_heap_t* heap, /* in: memory heap */
415
ulint n) /* in: number of bytes user needs */
418
mem_block_t* new_block;
421
ut_ad(mem_heap_check(heap));
423
block = UT_LIST_GET_LAST(heap->base);
425
/* We have to allocate a new block. The size is always at least
426
doubled until the standard size is reached. After that the size
427
stays the same, except in cases where the caller needs more space. */
429
new_size = 2 * mem_block_get_len(block);
431
if (heap->type != MEM_HEAP_DYNAMIC) {
432
/* From the buffer pool we allocate buffer frames */
433
ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
435
if (new_size > MEM_MAX_ALLOC_IN_BUF) {
436
new_size = MEM_MAX_ALLOC_IN_BUF;
438
} else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
440
new_size = MEM_BLOCK_STANDARD_SIZE;
447
new_block = mem_heap_create_block(heap, new_size, heap->type,
448
heap->file_name, heap->line);
449
if (new_block == NULL) {
454
/* Add the new block as the last block */
456
UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
461
/**********************************************************************
462
Frees a block from a memory heap. */
467
mem_heap_t* heap, /* in: heap */
468
mem_block_t* block) /* in: block to free */
472
buf_block_t* buf_block;
474
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
475
mem_analyze_corruption(block);
478
UT_LIST_REMOVE(list, heap->base, block);
480
#ifdef MEM_PERIODIC_CHECK
481
mem_pool_mutex_enter();
483
UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
485
mem_pool_mutex_exit();
489
buf_block = block->buf_block;
490
block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
492
#ifdef UNIV_MEM_DEBUG
493
/* In the debug version we set the memory to a random combination
494
of hex 0xDE and 0xAD. */
496
mem_erase_buf((byte*)block, len);
497
#else /* UNIV_MEM_DEBUG */
498
UNIV_MEM_ASSERT_AND_FREE(block, len);
499
#endif /* UNIV_MEM_DEBUG */
501
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
504
mem_area_free(block, mem_comm_pool);
506
ut_ad(type & MEM_HEAP_BUFFER);
508
buf_block_free(buf_block);
512
/**********************************************************************
513
Frees the free_block field from a memory heap. */
516
mem_heap_free_block_free(
517
/*=====================*/
518
mem_heap_t* heap) /* in: heap */
520
if (UNIV_LIKELY_NULL(heap->free_block)) {
522
buf_block_free(heap->free_block);
524
heap->free_block = NULL;
528
#ifdef MEM_PERIODIC_CHECK
529
/**********************************************************************
530
Goes through the list of all allocated mem blocks, checks their magic
531
numbers, and reports possible corruption. */
534
mem_validate_all_blocks(void)
535
/*=========================*/
539
mem_pool_mutex_enter();
541
block = UT_LIST_GET_FIRST(mem_block_list);
544
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
545
mem_analyze_corruption(block);
548
block = UT_LIST_GET_NEXT(mem_block_list, block);
551
mem_pool_mutex_exit();