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
/********************************************************************//**
21
The memory management: the debug code. This is not a compilation module,
22
but is included in mem0mem.* !
24
Created 6/9/1994 Heikki Tuuri
25
*************************************************************************/
28
# ifndef UNIV_HOTBACKUP
29
/* The mutex which protects in the debug version the hash table
30
containing the list of live memory heaps, and also the global
32
UNIV_INTERN mutex_t mem_hash_mutex;
33
# endif /* !UNIV_HOTBACKUP */
35
/* The following variables contain information about the
36
extent of memory allocations. Only used in the debug version.
37
Protected by mem_hash_mutex above. */
39
static ulint mem_n_created_heaps = 0;
40
static ulint mem_n_allocations = 0;
41
static ulint mem_total_allocated_memory = 0;
42
UNIV_INTERN ulint mem_current_allocated_memory = 0;
43
static ulint mem_max_allocated_memory = 0;
44
# ifndef UNIV_HOTBACKUP
45
static ulint mem_last_print_info = 0;
46
static ibool mem_hash_initialized = FALSE;
47
# endif /* !UNIV_HOTBACKUP */
49
/* Size of the hash table for memory management tracking */
50
#define MEM_HASH_SIZE 997
52
/* The node of the list containing currently allocated memory heaps */
54
typedef struct mem_hash_node_struct mem_hash_node_t;
55
struct mem_hash_node_struct {
56
UT_LIST_NODE_T(mem_hash_node_t)
57
list; /*!< hash list node */
58
mem_heap_t* heap; /*!< memory heap */
59
const char* file_name;/* file where heap was created*/
60
ulint line; /*!< file line of creation */
61
ulint nth_heap;/* this is the nth heap created */
62
UT_LIST_NODE_T(mem_hash_node_t)
63
all_list;/* list of all created heaps */
66
typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t;
68
/* The hash table of allocated heaps */
69
static mem_hash_cell_t mem_hash_table[MEM_HASH_SIZE];
71
/* The base node of the list of all allocated heaps */
72
static mem_hash_cell_t mem_all_list_base;
78
mem_hash_get_nth_cell(ulint i);
80
/* Accessor function for the hash table. Returns a pointer to the
84
mem_hash_get_nth_cell(ulint i)
86
ut_a(i < MEM_HASH_SIZE);
88
return(&(mem_hash_table[i]));
91
/* Accessor functions for a memory field in the debug version */
94
mem_field_header_set_len(byte* field, ulint len)
96
mach_write_to_4(field - 2 * sizeof(ulint), len);
101
mem_field_header_get_len(byte* field)
103
return(mach_read_from_4(field - 2 * sizeof(ulint)));
108
mem_field_header_set_check(byte* field, ulint check)
110
mach_write_to_4(field - sizeof(ulint), check);
115
mem_field_header_get_check(byte* field)
117
return(mach_read_from_4(field - sizeof(ulint)));
122
mem_field_trailer_set_check(byte* field, ulint check)
124
mach_write_to_4(field + mem_field_header_get_len(field), check);
129
mem_field_trailer_get_check(byte* field)
131
return(mach_read_from_4(field
132
+ mem_field_header_get_len(field)));
134
#endif /* UNIV_MEM_DEBUG */
136
#ifndef UNIV_HOTBACKUP
137
/******************************************************************//**
138
Initializes the memory system. */
143
ulint size) /*!< in: common pool size in bytes */
145
#ifdef UNIV_MEM_DEBUG
149
/* Initialize the hash table */
150
ut_a(FALSE == mem_hash_initialized);
152
mutex_create(&mem_hash_mutex, SYNC_MEM_HASH);
154
for (i = 0; i < MEM_HASH_SIZE; i++) {
155
UT_LIST_INIT(*mem_hash_get_nth_cell(i));
158
UT_LIST_INIT(mem_all_list_base);
160
mem_hash_initialized = TRUE;
163
if (UNIV_LIKELY(srv_use_sys_malloc)) {
164
/* When innodb_use_sys_malloc is set, the
165
mem_comm_pool won't be used for any allocations. We
166
create a dummy mem_comm_pool, because some statistics
167
and debugging code relies on it being initialized. */
171
mem_comm_pool = mem_pool_create(size);
173
#endif /* !UNIV_HOTBACKUP */
175
#ifdef UNIV_MEM_DEBUG
176
/******************************************************************//**
177
Initializes an allocated memory field in the debug version. */
182
byte* buf, /*!< in: memory field */
183
ulint n) /*!< in: how many bytes the user requested */
188
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
190
/* In the debug version write the length field and the
191
check fields to the start and the end of the allocated storage.
192
The field header consists of a length field and
193
a random number field, in this order. The field trailer contains
194
the same random number as a check field. */
196
mem_field_header_set_len(usr_buf, n);
198
rnd = ut_rnd_gen_ulint();
200
mem_field_header_set_check(usr_buf, rnd);
201
mem_field_trailer_set_check(usr_buf, rnd);
203
/* Update the memory allocation information */
205
mutex_enter(&mem_hash_mutex);
207
mem_total_allocated_memory += n;
208
mem_current_allocated_memory += n;
211
if (mem_current_allocated_memory > mem_max_allocated_memory) {
212
mem_max_allocated_memory = mem_current_allocated_memory;
215
mutex_exit(&mem_hash_mutex);
217
/* In the debug version set the buffer to a random
218
combination of 0xBA and 0xBE */
220
mem_init_buf(usr_buf, n);
223
/******************************************************************//**
224
Erases an allocated memory field in the debug version. */
229
byte* buf, /*!< in: memory field */
230
ulint n __attribute__((unused)))
231
/*!< in: how many bytes the user requested */
235
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
237
mutex_enter(&mem_hash_mutex);
238
mem_current_allocated_memory -= n;
239
mutex_exit(&mem_hash_mutex);
241
/* Check that the field lengths agree */
242
ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
244
/* In the debug version, set the freed space to a random
245
combination of 0xDE and 0xAD */
247
mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
250
/***************************************************************//**
251
Initializes a buffer to a random combination of hex BA and BE.
252
Used to initialize allocated memory. */
257
byte* buf, /*!< in: pointer to buffer */
258
ulint n) /*!< in: length of buffer */
262
UNIV_MEM_ASSERT_W(buf, n);
264
for (ptr = buf; ptr < buf + n; ptr++) {
266
if (ut_rnd_gen_ibool()) {
273
UNIV_MEM_INVALID(buf, n);
276
/***************************************************************//**
277
Initializes a buffer to a random combination of hex DE and AD.
278
Used to erase freed memory. */
283
byte* buf, /*!< in: pointer to buffer */
284
ulint n) /*!< in: length of buffer */
288
UNIV_MEM_ASSERT_W(buf, n);
290
for (ptr = buf; ptr < buf + n; ptr++) {
291
if (ut_rnd_gen_ibool()) {
298
UNIV_MEM_FREE(buf, n);
301
/***************************************************************//**
302
Inserts a created memory heap to the hash table of current allocated
308
mem_heap_t* heap, /*!< in: the created heap */
309
const char* file_name, /*!< in: file name of creation */
310
ulint line) /*!< in: line where created */
312
mem_hash_node_t* new_node;
315
ut_ad(mem_heap_check(heap));
317
mutex_enter(&mem_hash_mutex);
319
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
321
/* Allocate a new node to the list */
322
new_node = ut_malloc(sizeof(mem_hash_node_t));
324
new_node->heap = heap;
325
new_node->file_name = file_name;
326
new_node->line = line;
327
new_node->nth_heap = mem_n_created_heaps;
329
/* Insert into lists */
330
UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
332
UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
334
mem_n_created_heaps++;
336
mutex_exit(&mem_hash_mutex);
339
/***************************************************************//**
340
Removes a memory heap (which is going to be freed by the caller)
341
from the list of live memory heaps. Returns the size of the heap
342
in terms of how much memory in bytes was allocated for the user of
343
the heap (not the total space occupied by the heap).
344
Also validates the heap.
345
NOTE: This function does not free the storage occupied by the
346
heap itself, only the node in the list of heaps. */
351
mem_heap_t* heap, /*!< in: the heap to be freed */
352
const char* file_name, /*!< in: file name of freeing */
353
ulint line) /*!< in: line where freed */
355
mem_hash_node_t* node;
360
ut_ad(mem_heap_check(heap));
362
mutex_enter(&mem_hash_mutex);
364
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
366
/* Look for the heap in the hash table list */
367
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
369
while (node != NULL) {
370
if (node->heap == heap) {
375
node = UT_LIST_GET_NEXT(list, node);
380
"Memory heap or buffer freed in %s line %lu"
382
file_name, (ulong) line);
386
/* Remove from lists */
387
UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
389
UT_LIST_REMOVE(all_list, mem_all_list_base, node);
391
/* Validate the heap which will be freed */
392
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
396
"Inconsistency in memory heap or"
397
" buffer n:o %lu created\n"
398
"in %s line %lu and tried to free in %s line %lu.\n"
399
"Hex dump of 400 bytes around memory heap"
400
" first block start:\n",
401
node->nth_heap, node->file_name, (ulong) node->line,
402
file_name, (ulong) line);
403
ut_print_buf(stderr, (byte*)node->heap - 200, 400);
404
fputs("\nDump of the mem heap:\n", stderr);
405
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
410
/* Free the memory occupied by the node struct */
413
mem_current_allocated_memory -= size;
415
mutex_exit(&mem_hash_mutex);
417
#endif /* UNIV_MEM_DEBUG */
419
#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
420
/***************************************************************//**
421
Checks a memory heap for consistency and prints the contents if requested.
422
Outputs the sum of sizes of buffers given to the user (only in
423
the debug version), the physical size of the heap and the number of
424
blocks in the heap. In case of error returns 0 as sizes and number
428
mem_heap_validate_or_print(
429
/*=======================*/
430
mem_heap_t* heap, /*!< in: memory heap */
431
byte* top __attribute__((unused)),
432
/*!< in: calculate and validate only until
433
this top pointer in the heap is reached,
434
if this pointer is NULL, ignored */
435
ibool print, /*!< in: if TRUE, prints the contents
436
of the heap; works only in
438
ibool* error, /*!< out: TRUE if error */
439
ulint* us_size,/*!< out: allocated memory
440
(for the user) in the heap,
441
if a NULL pointer is passed as this
442
argument, it is ignored; in the
443
non-debug version this is always -1 */
444
ulint* ph_size,/*!< out: physical size of the heap,
445
if a NULL pointer is passed as this
446
argument, it is ignored */
447
ulint* n_blocks) /*!< out: number of blocks in the heap,
448
if a NULL pointer is passed as this
449
argument, it is ignored */
453
ulint block_count = 0;
455
#ifdef UNIV_MEM_DEBUG
462
/* Pessimistically, we set the parameters to error values */
463
if (us_size != NULL) {
466
if (ph_size != NULL) {
469
if (n_blocks != NULL) {
476
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
481
fputs("Memory heap:", stderr);
484
while (block != NULL) {
485
phys_len += mem_block_get_len(block);
487
if ((block->type == MEM_HEAP_BUFFER)
488
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
491
"InnoDB: Error: mem block %p"
492
" length %lu > UNIV_PAGE_SIZE\n",
494
(ulong) mem_block_get_len(block));
500
#ifdef UNIV_MEM_DEBUG
501
/* We can trace the fields of the block only in the debug
504
fprintf(stderr, " Block %ld:", block_count);
507
field = (byte*)block + mem_block_get_start(block);
509
if (top && (field == top)) {
514
while (field < (byte*)block + mem_block_get_free(block)) {
516
/* Calculate the pointer to the storage
517
which was given to the user */
519
user_field = field + MEM_FIELD_HEADER_SIZE;
521
len = mem_field_header_get_len(user_field);
524
ut_print_buf(stderr, user_field, len);
529
check_field = mem_field_header_get_check(user_field);
532
!= mem_field_trailer_get_check(user_field)) {
536
"InnoDB: Error: block %lx mem"
537
" field %lx len %lu\n"
538
"InnoDB: header check field is"
539
" %lx but trailer %lx\n",
541
(ulint)field, len, check_field,
542
mem_field_trailer_get_check(
548
/* Move to next field */
549
field = field + MEM_SPACE_NEEDED(len);
551
if (top && (field == top)) {
558
/* At the end check that we have arrived to the first free
561
if (field != (byte*)block + mem_block_get_free(block)) {
565
"InnoDB: Error: block %lx end of"
567
"InnoDB: but block free at %lx\n",
568
(ulint)block, (ulint)field,
570
+ mem_block_get_free(block)));
577
block = UT_LIST_GET_NEXT(list, block);
580
#ifdef UNIV_MEM_DEBUG
583
if (us_size != NULL) {
584
*us_size = total_len;
586
if (ph_size != NULL) {
589
if (n_blocks != NULL) {
590
*n_blocks = block_count;
595
/**************************************************************//**
596
Prints the contents of a memory heap. */
601
mem_heap_t* heap) /*!< in: memory heap */
608
ut_ad(mem_heap_check(heap));
610
mem_heap_validate_or_print(heap, NULL, TRUE, &error,
611
&us_size, &phys_size, &n_blocks);
613
"\nheap type: %lu; size: user size %lu;"
614
" physical size %lu; blocks %lu.\n",
615
(ulong) heap->type, (ulong) us_size,
616
(ulong) phys_size, (ulong) n_blocks);
620
/**************************************************************//**
621
Validates the contents of a memory heap.
622
@return TRUE if ok */
627
mem_heap_t* heap) /*!< in: memory heap */
634
ut_ad(mem_heap_check(heap));
636
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
637
&phys_size, &n_blocks);
639
mem_heap_print(heap);
646
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
649
/**************************************************************//**
650
Checks that an object is a memory heap (or a block of it).
651
@return TRUE if ok */
656
mem_heap_t* heap) /*!< in: memory heap */
658
ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
662
#endif /* UNIV_DEBUG */
664
#ifdef UNIV_MEM_DEBUG
665
/*****************************************************************//**
666
TRUE if no memory is currently allocated.
667
@return TRUE if no heaps exist */
673
mem_hash_node_t* node;
674
ulint heap_count = 0;
679
mutex_enter(&mem_hash_mutex);
681
for (i = 0; i < MEM_HASH_SIZE; i++) {
683
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
684
while (node != NULL) {
686
node = UT_LIST_GET_NEXT(list, node);
690
mutex_exit(&mem_hash_mutex);
692
if (heap_count == 0) {
693
# ifndef UNIV_HOTBACKUP
694
ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
695
# endif /* !UNIV_HOTBACKUP */
703
/*****************************************************************//**
704
Validates the dynamic memory allocation system.
705
@return TRUE if error */
708
mem_validate_no_assert(void)
709
/*========================*/
711
mem_hash_node_t* node;
715
ulint total_allocated_mem = 0;
720
# ifndef UNIV_HOTBACKUP
721
mem_pool_validate(mem_comm_pool);
722
# endif /* !UNIV_HOTBACKUP */
724
mutex_enter(&mem_hash_mutex);
726
for (i = 0; i < MEM_HASH_SIZE; i++) {
728
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
730
while (node != NULL) {
733
mem_heap_validate_or_print(node->heap, NULL,
736
&ph_size, &n_blocks);
740
"\nERROR!!!!!!!!!!!!!!!!!!!"
741
"!!!!!!!!!!!!!!!!!!!!!!!\n\n"
742
"Inconsistency in memory heap"
743
" or buffer created\n"
745
node->file_name, node->line);
747
mutex_exit(&mem_hash_mutex);
752
total_allocated_mem += allocated_mem;
753
node = UT_LIST_GET_NEXT(list, node);
757
if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
761
if (mem_total_allocated_memory < mem_current_allocated_memory) {
765
if (mem_max_allocated_memory > mem_total_allocated_memory) {
769
if (mem_n_created_heaps < n_heaps) {
773
mutex_exit(&mem_hash_mutex);
778
/************************************************************//**
779
Validates the dynamic memory
780
@return TRUE if ok */
786
ut_a(!mem_validate_no_assert());
790
#endif /* UNIV_MEM_DEBUG */
792
/************************************************************//**
793
Tries to find neigboring memory allocation blocks and dumps to stderr
794
the neighborhood of a given pointer. */
797
mem_analyze_corruption(
798
/*===================*/
799
void* ptr) /*!< in: pointer to place of possible corruption */
805
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
806
ut_print_buf(stderr, (byte*)ptr - 250, 500);
808
fputs("\nInnoDB: Scanning backward trying to find"
809
" previous allocated mem blocks\n", stderr);
814
for (i = 0; i < 10; i++) {
816
if (((ulint)p) % 4 == 0) {
818
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
820
"Mem block at - %lu,"
821
" file %s, line %lu\n",
831
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
833
"Freed mem block at - %lu,"
834
" file %s, line %lu\n",
854
"InnoDB: Scanning forward trying to find next"
855
" allocated mem blocks\n");
860
for (i = 0; i < 10; i++) {
862
if (((ulint)p) % 4 == 0) {
864
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
866
"Mem block at + %lu, file %s,"
877
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
879
"Freed mem block at + %lu,"
880
" file %s, line %lu\n",
900
#ifndef UNIV_HOTBACKUP
901
/*****************************************************************//**
902
Prints information of dynamic memory usage and currently allocated
903
memory heaps or buffers. Can only be used in the debug version. */
908
ibool print_all) /*!< in: if TRUE, all heaps are printed,
909
else only the heaps allocated after the
910
previous call of this function */
912
#ifdef UNIV_MEM_DEBUG
913
mem_hash_node_t* node;
917
ulint total_allocated_mem = 0;
923
/* outfile = fopen("ibdebug", "a"); */
927
fprintf(outfile, "\n");
929
"________________________________________________________\n");
930
fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
932
#ifndef UNIV_MEM_DEBUG
934
UT_NOT_USED(print_all);
936
mem_pool_print_info(outfile, mem_comm_pool);
939
"Sorry, non-debug version cannot give more memory info\n");
941
/* fclose(outfile); */
945
mutex_enter(&mem_hash_mutex);
947
fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
950
fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
953
node = UT_LIST_GET_FIRST(mem_all_list_base);
955
while (node != NULL) {
958
if (!print_all && node->nth_heap < mem_last_print_info) {
963
mem_heap_validate_or_print(node->heap, NULL,
964
FALSE, &error, &allocated_mem,
965
&ph_size, &n_blocks);
966
total_allocated_mem += allocated_mem;
969
"%lu: file %s line %lu of size %lu phys.size %lu"
970
" with %lu blocks, type %lu\n",
971
node->nth_heap, node->file_name, node->line,
972
allocated_mem, ph_size, n_blocks,
975
node = UT_LIST_GET_NEXT(all_list, node);
978
fprintf(outfile, "\n");
980
fprintf(outfile, "Current allocated memory : %lu\n",
981
mem_current_allocated_memory);
982
fprintf(outfile, "Current allocated heaps and buffers : %lu\n",
984
fprintf(outfile, "Cumulative allocated memory : %lu\n",
985
mem_total_allocated_memory);
986
fprintf(outfile, "Maximum allocated memory : %lu\n",
987
mem_max_allocated_memory);
988
fprintf(outfile, "Cumulative created heaps and buffers : %lu\n",
989
mem_n_created_heaps);
990
fprintf(outfile, "Cumulative number of allocations : %lu\n",
993
mem_last_print_info = mem_n_created_heaps;
995
mutex_exit(&mem_hash_mutex);
997
mem_pool_print_info(outfile, mem_comm_pool);
999
/* mem_validate(); */
1001
/* fclose(outfile); */
1005
/*****************************************************************//**
1006
Prints information of dynamic memory usage and currently allocated memory
1007
heaps or buffers. Can only be used in the debug version. */
1010
mem_print_info(void)
1011
/*================*/
1013
mem_print_info_low(TRUE);
1016
/*****************************************************************//**
1017
Prints information of dynamic memory usage and currently allocated memory
1018
heaps or buffers since the last ..._print_info or..._print_new_info. */
1021
mem_print_new_info(void)
1022
/*====================*/
1024
mem_print_info_low(FALSE);
1026
#endif /* !UNIV_HOTBACKUP */