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);
174
/******************************************************************//**
175
Closes the memory system. */
181
mem_pool_free(mem_comm_pool);
182
mem_comm_pool = NULL;
184
#endif /* !UNIV_HOTBACKUP */
186
#ifdef UNIV_MEM_DEBUG
187
/******************************************************************//**
188
Initializes an allocated memory field in the debug version. */
193
byte* buf, /*!< in: memory field */
194
ulint n) /*!< in: how many bytes the user requested */
199
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
201
/* In the debug version write the length field and the
202
check fields to the start and the end of the allocated storage.
203
The field header consists of a length field and
204
a random number field, in this order. The field trailer contains
205
the same random number as a check field. */
207
mem_field_header_set_len(usr_buf, n);
209
rnd = ut_rnd_gen_ulint();
211
mem_field_header_set_check(usr_buf, rnd);
212
mem_field_trailer_set_check(usr_buf, rnd);
214
/* Update the memory allocation information */
216
mutex_enter(&mem_hash_mutex);
218
mem_total_allocated_memory += n;
219
mem_current_allocated_memory += n;
222
if (mem_current_allocated_memory > mem_max_allocated_memory) {
223
mem_max_allocated_memory = mem_current_allocated_memory;
226
mutex_exit(&mem_hash_mutex);
228
/* In the debug version set the buffer to a random
229
combination of 0xBA and 0xBE */
231
mem_init_buf(usr_buf, n);
234
/******************************************************************//**
235
Erases an allocated memory field in the debug version. */
240
byte* buf, /*!< in: memory field */
241
ulint n __attribute__((unused)))
242
/*!< in: how many bytes the user requested */
246
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
248
mutex_enter(&mem_hash_mutex);
249
mem_current_allocated_memory -= n;
250
mutex_exit(&mem_hash_mutex);
252
/* Check that the field lengths agree */
253
ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
255
/* In the debug version, set the freed space to a random
256
combination of 0xDE and 0xAD */
258
mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
261
/***************************************************************//**
262
Initializes a buffer to a random combination of hex BA and BE.
263
Used to initialize allocated memory. */
268
byte* buf, /*!< in: pointer to buffer */
269
ulint n) /*!< in: length of buffer */
273
UNIV_MEM_ASSERT_W(buf, n);
275
for (ptr = buf; ptr < buf + n; ptr++) {
277
if (ut_rnd_gen_ibool()) {
284
UNIV_MEM_INVALID(buf, n);
287
/***************************************************************//**
288
Initializes a buffer to a random combination of hex DE and AD.
289
Used to erase freed memory. */
294
byte* buf, /*!< in: pointer to buffer */
295
ulint n) /*!< in: length of buffer */
299
UNIV_MEM_ASSERT_W(buf, n);
301
for (ptr = buf; ptr < buf + n; ptr++) {
302
if (ut_rnd_gen_ibool()) {
309
UNIV_MEM_FREE(buf, n);
312
/***************************************************************//**
313
Inserts a created memory heap to the hash table of current allocated
319
mem_heap_t* heap, /*!< in: the created heap */
320
const char* file_name, /*!< in: file name of creation */
321
ulint line) /*!< in: line where created */
323
mem_hash_node_t* new_node;
326
ut_ad(mem_heap_check(heap));
328
mutex_enter(&mem_hash_mutex);
330
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
332
/* Allocate a new node to the list */
333
new_node = ut_malloc(sizeof(mem_hash_node_t));
335
new_node->heap = heap;
336
new_node->file_name = file_name;
337
new_node->line = line;
338
new_node->nth_heap = mem_n_created_heaps;
340
/* Insert into lists */
341
UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
343
UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
345
mem_n_created_heaps++;
347
mutex_exit(&mem_hash_mutex);
350
/***************************************************************//**
351
Removes a memory heap (which is going to be freed by the caller)
352
from the list of live memory heaps. Returns the size of the heap
353
in terms of how much memory in bytes was allocated for the user of
354
the heap (not the total space occupied by the heap).
355
Also validates the heap.
356
NOTE: This function does not free the storage occupied by the
357
heap itself, only the node in the list of heaps. */
362
mem_heap_t* heap, /*!< in: the heap to be freed */
363
const char* file_name, /*!< in: file name of freeing */
364
ulint line) /*!< in: line where freed */
366
mem_hash_node_t* node;
371
ut_ad(mem_heap_check(heap));
373
mutex_enter(&mem_hash_mutex);
375
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
377
/* Look for the heap in the hash table list */
378
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
380
while (node != NULL) {
381
if (node->heap == heap) {
386
node = UT_LIST_GET_NEXT(list, node);
391
"Memory heap or buffer freed in %s line %lu"
393
file_name, (ulong) line);
397
/* Remove from lists */
398
UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
400
UT_LIST_REMOVE(all_list, mem_all_list_base, node);
402
/* Validate the heap which will be freed */
403
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
407
"Inconsistency in memory heap or"
408
" buffer n:o %lu created\n"
409
"in %s line %lu and tried to free in %s line %lu.\n"
410
"Hex dump of 400 bytes around memory heap"
411
" first block start:\n",
412
node->nth_heap, node->file_name, (ulong) node->line,
413
file_name, (ulong) line);
414
ut_print_buf(stderr, (byte*)node->heap - 200, 400);
415
fputs("\nDump of the mem heap:\n", stderr);
416
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
421
/* Free the memory occupied by the node struct */
424
mem_current_allocated_memory -= size;
426
mutex_exit(&mem_hash_mutex);
428
#endif /* UNIV_MEM_DEBUG */
430
#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
431
/***************************************************************//**
432
Checks a memory heap for consistency and prints the contents if requested.
433
Outputs the sum of sizes of buffers given to the user (only in
434
the debug version), the physical size of the heap and the number of
435
blocks in the heap. In case of error returns 0 as sizes and number
439
mem_heap_validate_or_print(
440
/*=======================*/
441
mem_heap_t* heap, /*!< in: memory heap */
442
byte* top __attribute__((unused)),
443
/*!< in: calculate and validate only until
444
this top pointer in the heap is reached,
445
if this pointer is NULL, ignored */
446
ibool print, /*!< in: if TRUE, prints the contents
447
of the heap; works only in
449
ibool* error, /*!< out: TRUE if error */
450
ulint* us_size,/*!< out: allocated memory
451
(for the user) in the heap,
452
if a NULL pointer is passed as this
453
argument, it is ignored; in the
454
non-debug version this is always -1 */
455
ulint* ph_size,/*!< out: physical size of the heap,
456
if a NULL pointer is passed as this
457
argument, it is ignored */
458
ulint* n_blocks) /*!< out: number of blocks in the heap,
459
if a NULL pointer is passed as this
460
argument, it is ignored */
464
ulint block_count = 0;
466
#ifdef UNIV_MEM_DEBUG
473
/* Pessimistically, we set the parameters to error values */
474
if (us_size != NULL) {
477
if (ph_size != NULL) {
480
if (n_blocks != NULL) {
487
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
492
fputs("Memory heap:", stderr);
495
while (block != NULL) {
496
phys_len += mem_block_get_len(block);
498
if ((block->type == MEM_HEAP_BUFFER)
499
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
502
"InnoDB: Error: mem block %p"
503
" length %lu > UNIV_PAGE_SIZE\n",
505
(ulong) mem_block_get_len(block));
511
#ifdef UNIV_MEM_DEBUG
512
/* We can trace the fields of the block only in the debug
515
fprintf(stderr, " Block %ld:", block_count);
518
field = (byte*)block + mem_block_get_start(block);
520
if (top && (field == top)) {
525
while (field < (byte*)block + mem_block_get_free(block)) {
527
/* Calculate the pointer to the storage
528
which was given to the user */
530
user_field = field + MEM_FIELD_HEADER_SIZE;
532
len = mem_field_header_get_len(user_field);
535
ut_print_buf(stderr, user_field, len);
540
check_field = mem_field_header_get_check(user_field);
543
!= mem_field_trailer_get_check(user_field)) {
547
"InnoDB: Error: block %lx mem"
548
" field %lx len %lu\n"
549
"InnoDB: header check field is"
550
" %lx but trailer %lx\n",
552
(ulint)field, len, check_field,
553
mem_field_trailer_get_check(
559
/* Move to next field */
560
field = field + MEM_SPACE_NEEDED(len);
562
if (top && (field == top)) {
569
/* At the end check that we have arrived to the first free
572
if (field != (byte*)block + mem_block_get_free(block)) {
576
"InnoDB: Error: block %lx end of"
578
"InnoDB: but block free at %lx\n",
579
(ulint)block, (ulint)field,
581
+ mem_block_get_free(block)));
588
block = UT_LIST_GET_NEXT(list, block);
591
#ifdef UNIV_MEM_DEBUG
594
if (us_size != NULL) {
595
*us_size = total_len;
597
if (ph_size != NULL) {
600
if (n_blocks != NULL) {
601
*n_blocks = block_count;
606
/**************************************************************//**
607
Prints the contents of a memory heap. */
612
mem_heap_t* heap) /*!< in: memory heap */
619
ut_ad(mem_heap_check(heap));
621
mem_heap_validate_or_print(heap, NULL, TRUE, &error,
622
&us_size, &phys_size, &n_blocks);
624
"\nheap type: %lu; size: user size %lu;"
625
" physical size %lu; blocks %lu.\n",
626
(ulong) heap->type, (ulong) us_size,
627
(ulong) phys_size, (ulong) n_blocks);
631
/**************************************************************//**
632
Validates the contents of a memory heap.
633
@return TRUE if ok */
638
mem_heap_t* heap) /*!< in: memory heap */
645
ut_ad(mem_heap_check(heap));
647
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
648
&phys_size, &n_blocks);
650
mem_heap_print(heap);
657
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
660
/**************************************************************//**
661
Checks that an object is a memory heap (or a block of it).
662
@return TRUE if ok */
667
mem_heap_t* heap) /*!< in: memory heap */
669
ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
673
#endif /* UNIV_DEBUG */
675
#ifdef UNIV_MEM_DEBUG
676
/*****************************************************************//**
677
TRUE if no memory is currently allocated.
678
@return TRUE if no heaps exist */
684
mem_hash_node_t* node;
685
ulint heap_count = 0;
690
mutex_enter(&mem_hash_mutex);
692
for (i = 0; i < MEM_HASH_SIZE; i++) {
694
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
695
while (node != NULL) {
697
node = UT_LIST_GET_NEXT(list, node);
701
mutex_exit(&mem_hash_mutex);
703
if (heap_count == 0) {
704
# ifndef UNIV_HOTBACKUP
705
ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
706
# endif /* !UNIV_HOTBACKUP */
714
/*****************************************************************//**
715
Validates the dynamic memory allocation system.
716
@return TRUE if error */
719
mem_validate_no_assert(void)
720
/*========================*/
722
mem_hash_node_t* node;
726
ulint total_allocated_mem = 0;
731
# ifndef UNIV_HOTBACKUP
732
mem_pool_validate(mem_comm_pool);
733
# endif /* !UNIV_HOTBACKUP */
735
mutex_enter(&mem_hash_mutex);
737
for (i = 0; i < MEM_HASH_SIZE; i++) {
739
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
741
while (node != NULL) {
744
mem_heap_validate_or_print(node->heap, NULL,
747
&ph_size, &n_blocks);
751
"\nERROR!!!!!!!!!!!!!!!!!!!"
752
"!!!!!!!!!!!!!!!!!!!!!!!\n\n"
753
"Inconsistency in memory heap"
754
" or buffer created\n"
756
node->file_name, node->line);
758
mutex_exit(&mem_hash_mutex);
763
total_allocated_mem += allocated_mem;
764
node = UT_LIST_GET_NEXT(list, node);
768
if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
772
if (mem_total_allocated_memory < mem_current_allocated_memory) {
776
if (mem_max_allocated_memory > mem_total_allocated_memory) {
780
if (mem_n_created_heaps < n_heaps) {
784
mutex_exit(&mem_hash_mutex);
789
/************************************************************//**
790
Validates the dynamic memory
791
@return TRUE if ok */
797
ut_a(!mem_validate_no_assert());
801
#endif /* UNIV_MEM_DEBUG */
803
/************************************************************//**
804
Tries to find neigboring memory allocation blocks and dumps to stderr
805
the neighborhood of a given pointer. */
808
mem_analyze_corruption(
809
/*===================*/
810
void* ptr) /*!< in: pointer to place of possible corruption */
816
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
817
ut_print_buf(stderr, (byte*)ptr - 250, 500);
819
fputs("\nInnoDB: Scanning backward trying to find"
820
" previous allocated mem blocks\n", stderr);
825
for (i = 0; i < 10; i++) {
827
if (((ulint)p) % 4 == 0) {
829
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
831
"Mem block at - %lu,"
832
" file %s, line %lu\n",
842
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
844
"Freed mem block at - %lu,"
845
" file %s, line %lu\n",
865
"InnoDB: Scanning forward trying to find next"
866
" allocated mem blocks\n");
871
for (i = 0; i < 10; i++) {
873
if (((ulint)p) % 4 == 0) {
875
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
877
"Mem block at + %lu, file %s,"
888
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
890
"Freed mem block at + %lu,"
891
" file %s, line %lu\n",
911
#ifndef UNIV_HOTBACKUP
912
/*****************************************************************//**
913
Prints information of dynamic memory usage and currently allocated
914
memory heaps or buffers. Can only be used in the debug version. */
919
ibool print_all) /*!< in: if TRUE, all heaps are printed,
920
else only the heaps allocated after the
921
previous call of this function */
923
#ifdef UNIV_MEM_DEBUG
924
mem_hash_node_t* node;
928
ulint total_allocated_mem = 0;
934
/* outfile = fopen("ibdebug", "a"); */
938
fprintf(outfile, "\n");
940
"________________________________________________________\n");
941
fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
943
#ifndef UNIV_MEM_DEBUG
945
UT_NOT_USED(print_all);
947
mem_pool_print_info(outfile, mem_comm_pool);
950
"Sorry, non-debug version cannot give more memory info\n");
952
/* fclose(outfile); */
956
mutex_enter(&mem_hash_mutex);
958
fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
961
fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
964
node = UT_LIST_GET_FIRST(mem_all_list_base);
966
while (node != NULL) {
969
if (!print_all && node->nth_heap < mem_last_print_info) {
974
mem_heap_validate_or_print(node->heap, NULL,
975
FALSE, &error, &allocated_mem,
976
&ph_size, &n_blocks);
977
total_allocated_mem += allocated_mem;
980
"%lu: file %s line %lu of size %lu phys.size %lu"
981
" with %lu blocks, type %lu\n",
982
node->nth_heap, node->file_name, node->line,
983
allocated_mem, ph_size, n_blocks,
986
node = UT_LIST_GET_NEXT(all_list, node);
989
fprintf(outfile, "\n");
991
fprintf(outfile, "Current allocated memory : %lu\n",
992
mem_current_allocated_memory);
993
fprintf(outfile, "Current allocated heaps and buffers : %lu\n",
995
fprintf(outfile, "Cumulative allocated memory : %lu\n",
996
mem_total_allocated_memory);
997
fprintf(outfile, "Maximum allocated memory : %lu\n",
998
mem_max_allocated_memory);
999
fprintf(outfile, "Cumulative created heaps and buffers : %lu\n",
1000
mem_n_created_heaps);
1001
fprintf(outfile, "Cumulative number of allocations : %lu\n",
1004
mem_last_print_info = mem_n_created_heaps;
1006
mutex_exit(&mem_hash_mutex);
1008
mem_pool_print_info(outfile, mem_comm_pool);
1010
/* mem_validate(); */
1012
/* fclose(outfile); */
1016
/*****************************************************************//**
1017
Prints information of dynamic memory usage and currently allocated memory
1018
heaps or buffers. Can only be used in the debug version. */
1021
mem_print_info(void)
1022
/*================*/
1024
mem_print_info_low(TRUE);
1027
/*****************************************************************//**
1028
Prints information of dynamic memory usage and currently allocated memory
1029
heaps or buffers since the last ..._print_info or..._print_new_info. */
1032
mem_print_new_info(void)
1033
/*====================*/
1035
mem_print_info_low(FALSE);
1037
#endif /* !UNIV_HOTBACKUP */