1
/*****************************************************************************
3
Copyright (C) 1994, 2010, 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/********************************************************************//**
23
Created 6/9/1994 Heikki Tuuri
24
*************************************************************************/
41
The basic element of the memory management is called a memory
42
heap. A memory heap is conceptually a
43
stack from which memory can be allocated. The stack may grow infinitely.
44
The top element of the stack may be freed, or
45
the whole stack can be freed at one time. The advantage of the
46
memory heap concept is that we can avoid using the malloc and free
47
functions of C which are quite expensive, for example, on the Solaris + GCC
48
system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
49
on Win NT + 100MHz Pentium, 2.5 microseconds.
50
When we use a memory heap,
51
we can allocate larger blocks of memory at a time and thus
52
reduce overhead. Slightly more efficient the method is when we
53
allocate the memory from the index page buffer pool, as we can
54
claim a new page fast. This is called buffer allocation.
55
When we allocate the memory from the dynamic memory of the
56
C environment, that is called dynamic allocation.
58
The default way of operation of the memory heap is the following.
59
First, when the heap is created, an initial block of memory is
60
allocated. In dynamic allocation this may be about 50 bytes.
61
If more space is needed, additional blocks are allocated
62
and they are put into a linked list.
63
After the initial block, each allocated block is twice the size of the
64
previous, until a threshold is attained, after which the sizes
65
of the blocks stay the same. An exception is, of course, the case
66
where the caller requests a memory buffer whose size is
67
bigger than the threshold. In that case a block big enough must
70
The heap is physically arranged so that if the current block
71
becomes full, a new block is allocated and always inserted in the
72
chain of blocks as the last block.
74
In the debug version of the memory management, all the allocated
75
heaps are kept in a list (which is implemented as a hash table).
76
Thus we can notice if the caller tries to free an already freed
77
heap. In addition, each buffer given to the caller contains
78
start field at the start and a trailer field at the end of the buffer.
80
The start field has the following content:
81
A. sizeof(ulint) bytes of field length (in the standard byte order)
82
B. sizeof(ulint) bytes of check field (a random number)
84
The trailer field contains:
85
A. sizeof(ulint) bytes of check field (the same random number as at the start)
87
Thus we can notice if something has been copied over the
88
borders of the buffer, which is illegal.
89
The memory in the buffers is initialized to a random byte sequence.
90
After freeing, all the blocks in the heap are set to random bytes
91
to help us discover errors which result from the use of
92
buffers in an already freed heap. */
94
#ifdef MEM_PERIODIC_CHECK
96
ibool mem_block_list_inited;
97
/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
98
UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
102
/**********************************************************************//**
103
Duplicates a NUL-terminated string, allocated from a memory heap.
104
@return own: a copy of the string */
109
mem_heap_t* heap, /*!< in: memory heap where string is allocated */
110
const char* str) /*!< in: string to be copied */
112
return(static_cast<char *>(mem_heap_dup(heap, str, strlen(str) + 1)));
115
/**********************************************************************//**
116
Duplicate a block of data, allocated from a memory heap.
117
@return own: a copy of the data */
122
mem_heap_t* heap, /*!< in: memory heap where copy is allocated */
123
const void* data, /*!< in: data to be copied */
124
ulint len) /*!< in: length of data, in bytes */
126
return(memcpy(mem_heap_alloc(heap, len), data, len));
129
/**********************************************************************//**
130
Concatenate two strings and return the result, using a memory heap.
131
@return own: the result */
136
mem_heap_t* heap, /*!< in: memory heap where string is allocated */
137
const char* s1, /*!< in: string 1 */
138
const char* s2) /*!< in: string 2 */
141
ulint s1_len = strlen(s1);
142
ulint s2_len = strlen(s2);
144
s = static_cast<char *>(mem_heap_alloc(heap, s1_len + s2_len + 1));
146
memcpy(s, s1, s1_len);
147
memcpy(s + s1_len, s2, s2_len);
149
s[s1_len + s2_len] = '\0';
155
/****************************************************************//**
156
Helper function for mem_heap_printf.
157
@return length of formatted string, including terminating NUL */
162
char* buf, /*!< in/out: buffer to store formatted string
163
in, or NULL to just calculate length */
164
const char* format, /*!< in: format string */
165
va_list ap) /*!< in: arguments */
171
/* Does this format specifier have the 'l' length modifier. */
172
ibool is_long = FALSE;
174
/* Length of one parameter. */
177
if (*format++ != '%') {
178
/* Non-format character. */
183
*buf++ = *(format - 1);
189
if (*format == 'l') {
198
char* s = va_arg(ap, char*);
200
/* "%ls" is a non-sensical format specifier. */
207
memcpy(buf, s, plen);
220
/* We only support 'long' values for now. */
223
val = va_arg(ap, unsigned long);
225
plen = sprintf(tmp, "%lu", val);
229
memcpy(buf, tmp, plen);
238
/* "%l%" is a non-sensical format specifier. */
254
/* For the NUL character. */
264
/****************************************************************//**
265
A simple (s)printf replacement that dynamically allocates the space for the
266
formatted string from the given heap. This supports a very limited set of
267
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
268
required for the 'u' type).
269
@return heap-allocated formatted string */
274
mem_heap_t* heap, /*!< in: memory heap */
275
const char* format, /*!< in: format string */
282
/* Calculate length of string */
284
va_start(ap, format);
285
len = mem_heap_printf_low(NULL, format, ap);
288
/* Now create it for real. */
289
str = static_cast<char *>(mem_heap_alloc(heap, len));
290
va_start(ap, format);
291
mem_heap_printf_low(str, format, ap);
297
/***************************************************************//**
298
Creates a memory heap block where data can be allocated.
299
@return own: memory heap block, NULL if did not succeed (only possible
300
for MEM_HEAP_BTR_SEARCH type heaps) */
303
mem_heap_create_block(
304
/*==================*/
305
mem_heap_t* heap, /*!< in: memory heap or NULL if first block
307
ulint n, /*!< in: number of bytes needed for user data */
308
ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or
310
const char* file_name,/*!< in: file name where created */
311
ulint line) /*!< in: line where created */
313
#ifndef UNIV_HOTBACKUP
314
buf_block_t* buf_block = NULL;
315
#endif /* !UNIV_HOTBACKUP */
319
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
320
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
322
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
323
mem_analyze_corruption(heap);
326
/* In dynamic allocation, calculate the size: block header + data. */
327
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
329
#ifndef UNIV_HOTBACKUP
330
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
332
ut_ad(type == MEM_HEAP_DYNAMIC || n <= MEM_MAX_ALLOC_IN_BUF);
334
block = static_cast<mem_block_info_t *>(mem_area_alloc(&len, mem_comm_pool));
336
len = UNIV_PAGE_SIZE;
338
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
339
/* We cannot allocate the block from the
340
buffer pool, but must get the free block from
341
the heap header free block field */
343
buf_block = static_cast<buf_block_t *>(heap->free_block);
344
heap->free_block = NULL;
346
if (UNIV_UNLIKELY(!buf_block)) {
351
buf_block = buf_block_alloc(NULL, 0);
354
block = (mem_block_t*) buf_block->frame;
358
block->buf_block = buf_block;
359
block->free_block = NULL;
360
#else /* !UNIV_HOTBACKUP */
361
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
362
block = ut_malloc(len);
364
#endif /* !UNIV_HOTBACKUP */
366
block->magic_n = MEM_BLOCK_MAGIC_N;
367
ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
370
#ifdef MEM_PERIODIC_CHECK
371
mutex_enter(&(mem_comm_pool->mutex));
373
if (!mem_block_list_inited) {
374
mem_block_list_inited = TRUE;
375
UT_LIST_INIT(mem_block_list);
378
UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
380
mutex_exit(&(mem_comm_pool->mutex));
382
mem_block_set_len(block, len);
383
mem_block_set_type(block, type);
384
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
385
mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
387
if (UNIV_UNLIKELY(heap == NULL)) {
388
/* This is the first block of the heap. The field
389
total_size should be initialized here */
390
block->total_size = len;
392
/* Not the first allocation for the heap. This block's
393
total_length field should be set to undefined. */
394
ut_d(block->total_size = ULINT_UNDEFINED);
395
UNIV_MEM_INVALID(&block->total_size,
396
sizeof block->total_size);
398
heap->total_size += len;
401
ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
406
/***************************************************************//**
407
Adds a new block to a memory heap.
408
@return created block, NULL if did not succeed (only possible for
409
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
#ifndef UNIV_HOTBACKUP
473
buf_block_t* buf_block = static_cast<buf_block_t *>(block->buf_block);
474
#endif /* !UNIV_HOTBACKUP */
476
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
477
mem_analyze_corruption(block);
480
UT_LIST_REMOVE(list, heap->base, block);
482
#ifdef MEM_PERIODIC_CHECK
483
mutex_enter(&(mem_comm_pool->mutex));
485
UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
487
mutex_exit(&(mem_comm_pool->mutex));
490
ut_ad(heap->total_size >= block->len);
491
heap->total_size -= block->len;
495
block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
497
#ifndef UNIV_HOTBACKUP
498
#ifdef UNIV_MEM_DEBUG
499
/* In the debug version we set the memory to a random combination
500
of hex 0xDE and 0xAD. */
502
mem_erase_buf((byte*)block, len);
503
#else /* UNIV_MEM_DEBUG */
504
UNIV_MEM_ASSERT_AND_FREE(block, len);
505
#endif /* UNIV_MEM_DEBUG */
507
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
510
mem_area_free(block, mem_comm_pool);
512
ut_ad(type & MEM_HEAP_BUFFER);
514
buf_block_free(buf_block);
516
#else /* !UNIV_HOTBACKUP */
517
#ifdef UNIV_MEM_DEBUG
518
/* In the debug version we set the memory to a random
519
combination of hex 0xDE and 0xAD. */
521
mem_erase_buf((byte*)block, len);
522
#else /* UNIV_MEM_DEBUG */
523
UNIV_MEM_ASSERT_AND_FREE(block, len);
524
#endif /* UNIV_MEM_DEBUG */
526
#endif /* !UNIV_HOTBACKUP */
529
#ifndef UNIV_HOTBACKUP
530
/******************************************************************//**
531
Frees the free_block field from a memory heap. */
534
mem_heap_free_block_free(
535
/*=====================*/
536
mem_heap_t* heap) /*!< in: heap */
538
if (UNIV_LIKELY_NULL(heap->free_block)) {
540
buf_block_free(static_cast<buf_block_t *>(heap->free_block));
542
heap->free_block = NULL;
545
#endif /* !UNIV_HOTBACKUP */
547
#ifdef MEM_PERIODIC_CHECK
548
/******************************************************************//**
549
Goes through the list of all allocated mem blocks, checks their magic
550
numbers, and reports possible corruption. */
553
mem_validate_all_blocks(void)
554
/*=========================*/
558
mutex_enter(&(mem_comm_pool->mutex));
560
block = UT_LIST_GET_FIRST(mem_block_list);
563
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
564
mem_analyze_corruption(block);
567
block = UT_LIST_GET_NEXT(mem_block_list, block);
570
mutex_exit(&(mem_comm_pool->mutex));