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
/********************************************************************//**
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;
35
/* Key to register mem_hash_mutex with performance schema */
36
UNIV_INTERN mysql_pfs_key_t mem_hash_mutex_key;
37
#endif /* UNIV_PFS_MUTEX */
39
# endif /* !UNIV_HOTBACKUP */
41
/* The following variables contain information about the
42
extent of memory allocations. Only used in the debug version.
43
Protected by mem_hash_mutex above. */
45
static ulint mem_n_created_heaps = 0;
46
static ulint mem_n_allocations = 0;
47
static ulint mem_total_allocated_memory = 0;
48
UNIV_INTERN ulint mem_current_allocated_memory = 0;
49
static ulint mem_max_allocated_memory = 0;
50
# ifndef UNIV_HOTBACKUP
51
static ulint mem_last_print_info = 0;
52
static ibool mem_hash_initialized = FALSE;
53
# endif /* !UNIV_HOTBACKUP */
55
/* Size of the hash table for memory management tracking */
56
#define MEM_HASH_SIZE 997
58
/* The node of the list containing currently allocated memory heaps */
60
typedef struct mem_hash_node_struct mem_hash_node_t;
61
struct mem_hash_node_struct {
62
UT_LIST_NODE_T(mem_hash_node_t)
63
list; /*!< hash list node */
64
mem_heap_t* heap; /*!< memory heap */
65
const char* file_name;/* file where heap was created*/
66
ulint line; /*!< file line of creation */
67
ulint nth_heap;/* this is the nth heap created */
68
UT_LIST_NODE_T(mem_hash_node_t)
69
all_list;/* list of all created heaps */
72
typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t;
74
/* The hash table of allocated heaps */
75
static mem_hash_cell_t mem_hash_table[MEM_HASH_SIZE];
77
/* The base node of the list of all allocated heaps */
78
static mem_hash_cell_t mem_all_list_base;
84
mem_hash_get_nth_cell(ulint i);
86
/* Accessor function for the hash table. Returns a pointer to the
90
mem_hash_get_nth_cell(ulint i)
92
ut_a(i < MEM_HASH_SIZE);
94
return(&(mem_hash_table[i]));
97
/* Accessor functions for a memory field in the debug version */
100
mem_field_header_set_len(byte* field, ulint len)
102
mach_write_to_4(field - 2 * sizeof(ulint), len);
107
mem_field_header_get_len(byte* field)
109
return(mach_read_from_4(field - 2 * sizeof(ulint)));
114
mem_field_header_set_check(byte* field, ulint check)
116
mach_write_to_4(field - sizeof(ulint), check);
121
mem_field_header_get_check(byte* field)
123
return(mach_read_from_4(field - sizeof(ulint)));
128
mem_field_trailer_set_check(byte* field, ulint check)
130
mach_write_to_4(field + mem_field_header_get_len(field), check);
135
mem_field_trailer_get_check(byte* field)
137
return(mach_read_from_4(field
138
+ mem_field_header_get_len(field)));
140
#endif /* UNIV_MEM_DEBUG */
142
#ifndef UNIV_HOTBACKUP
143
/******************************************************************//**
144
Initializes the memory system. */
149
ulint size) /*!< in: common pool size in bytes */
151
#ifdef UNIV_MEM_DEBUG
155
/* Initialize the hash table */
156
ut_a(FALSE == mem_hash_initialized);
158
mutex_create(mem_hash_mutex_key, &mem_hash_mutex, SYNC_MEM_HASH);
160
for (i = 0; i < MEM_HASH_SIZE; i++) {
161
UT_LIST_INIT(*mem_hash_get_nth_cell(i));
164
UT_LIST_INIT(mem_all_list_base);
166
mem_hash_initialized = TRUE;
169
if (UNIV_LIKELY(srv_use_sys_malloc)) {
170
/* When innodb_use_sys_malloc is set, the
171
mem_comm_pool won't be used for any allocations. We
172
create a dummy mem_comm_pool, because some statistics
173
and debugging code relies on it being initialized. */
177
mem_comm_pool = mem_pool_create(size);
180
/******************************************************************//**
181
Closes the memory system. */
187
mem_pool_free(mem_comm_pool);
188
mem_comm_pool = NULL;
189
#ifdef UNIV_MEM_DEBUG
190
mutex_free(&mem_hash_mutex);
191
mem_hash_initialized = FALSE;
192
#endif /* UNIV_MEM_DEBUG */
194
#endif /* !UNIV_HOTBACKUP */
196
#ifdef UNIV_MEM_DEBUG
197
/******************************************************************//**
198
Initializes an allocated memory field in the debug version. */
203
byte* buf, /*!< in: memory field */
204
ulint n) /*!< in: how many bytes the user requested */
209
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
211
/* In the debug version write the length field and the
212
check fields to the start and the end of the allocated storage.
213
The field header consists of a length field and
214
a random number field, in this order. The field trailer contains
215
the same random number as a check field. */
217
mem_field_header_set_len(usr_buf, n);
219
rnd = ut_rnd_gen_ulint();
221
mem_field_header_set_check(usr_buf, rnd);
222
mem_field_trailer_set_check(usr_buf, rnd);
224
/* Update the memory allocation information */
226
mutex_enter(&mem_hash_mutex);
228
mem_total_allocated_memory += n;
229
mem_current_allocated_memory += n;
232
if (mem_current_allocated_memory > mem_max_allocated_memory) {
233
mem_max_allocated_memory = mem_current_allocated_memory;
236
mutex_exit(&mem_hash_mutex);
238
/* In the debug version set the buffer to a random
239
combination of 0xBA and 0xBE */
241
mem_init_buf(usr_buf, n);
244
/******************************************************************//**
245
Erases an allocated memory field in the debug version. */
250
byte* buf, /*!< in: memory field */
251
ulint /*n __attribute__((unused))*/)
252
/*!< in: how many bytes the user requested */
256
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
258
mutex_enter(&mem_hash_mutex);
259
mem_current_allocated_memory -= n;
260
mutex_exit(&mem_hash_mutex);
262
/* Check that the field lengths agree */
263
ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
265
/* In the debug version, set the freed space to a random
266
combination of 0xDE and 0xAD */
268
mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
271
/***************************************************************//**
272
Initializes a buffer to a random combination of hex BA and BE.
273
Used to initialize allocated memory. */
278
byte* buf, /*!< in: pointer to buffer */
279
ulint n) /*!< in: length of buffer */
283
UNIV_MEM_ASSERT_W(buf, n);
285
for (ptr = buf; ptr < buf + n; ptr++) {
287
if (ut_rnd_gen_ibool()) {
294
UNIV_MEM_INVALID(buf, n);
297
/***************************************************************//**
298
Initializes a buffer to a random combination of hex DE and AD.
299
Used to erase freed memory. */
304
byte* buf, /*!< in: pointer to buffer */
305
ulint n) /*!< in: length of buffer */
309
UNIV_MEM_ASSERT_W(buf, n);
311
for (ptr = buf; ptr < buf + n; ptr++) {
312
if (ut_rnd_gen_ibool()) {
319
UNIV_MEM_FREE(buf, n);
322
/***************************************************************//**
323
Inserts a created memory heap to the hash table of current allocated
329
mem_heap_t* heap, /*!< in: the created heap */
330
const char* file_name, /*!< in: file name of creation */
331
ulint line) /*!< in: line where created */
333
mem_hash_node_t* new_node;
336
ut_ad(mem_heap_check(heap));
338
mutex_enter(&mem_hash_mutex);
340
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
342
/* Allocate a new node to the list */
343
new_node = ut_malloc(sizeof(mem_hash_node_t));
345
new_node->heap = heap;
346
new_node->file_name = file_name;
347
new_node->line = line;
348
new_node->nth_heap = mem_n_created_heaps;
350
/* Insert into lists */
351
UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
353
UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
355
mem_n_created_heaps++;
357
mutex_exit(&mem_hash_mutex);
360
/***************************************************************//**
361
Removes a memory heap (which is going to be freed by the caller)
362
from the list of live memory heaps. Returns the size of the heap
363
in terms of how much memory in bytes was allocated for the user of
364
the heap (not the total space occupied by the heap).
365
Also validates the heap.
366
NOTE: This function does not free the storage occupied by the
367
heap itself, only the node in the list of heaps. */
372
mem_heap_t* heap, /*!< in: the heap to be freed */
373
const char* file_name, /*!< in: file name of freeing */
374
ulint line) /*!< in: line where freed */
376
mem_hash_node_t* node;
381
ut_ad(mem_heap_check(heap));
383
mutex_enter(&mem_hash_mutex);
385
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
387
/* Look for the heap in the hash table list */
388
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
390
while (node != NULL) {
391
if (node->heap == heap) {
396
node = UT_LIST_GET_NEXT(list, node);
401
"Memory heap or buffer freed in %s line %lu"
403
file_name, (ulong) line);
407
/* Remove from lists */
408
UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
410
UT_LIST_REMOVE(all_list, mem_all_list_base, node);
412
/* Validate the heap which will be freed */
413
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
417
"Inconsistency in memory heap or"
418
" buffer n:o %lu created\n"
419
"in %s line %lu and tried to free in %s line %lu.\n"
420
"Hex dump of 400 bytes around memory heap"
421
" first block start:\n",
422
node->nth_heap, node->file_name, (ulong) node->line,
423
file_name, (ulong) line);
424
ut_print_buf(stderr, (byte*)node->heap - 200, 400);
425
fputs("\nDump of the mem heap:\n", stderr);
426
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
431
/* Free the memory occupied by the node struct */
434
mem_current_allocated_memory -= size;
436
mutex_exit(&mem_hash_mutex);
438
#endif /* UNIV_MEM_DEBUG */
440
#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
441
/***************************************************************//**
442
Checks a memory heap for consistency and prints the contents if requested.
443
Outputs the sum of sizes of buffers given to the user (only in
444
the debug version), the physical size of the heap and the number of
445
blocks in the heap. In case of error returns 0 as sizes and number
449
mem_heap_validate_or_print(
450
/*=======================*/
451
mem_heap_t* heap, /*!< in: memory heap */
452
byte* /*top __attribute__((unused))*/,
453
/*!< in: calculate and validate only until
454
this top pointer in the heap is reached,
455
if this pointer is NULL, ignored */
456
ibool print, /*!< in: if TRUE, prints the contents
457
of the heap; works only in
459
ibool* error, /*!< out: TRUE if error */
460
ulint* us_size,/*!< out: allocated memory
461
(for the user) in the heap,
462
if a NULL pointer is passed as this
463
argument, it is ignored; in the
464
non-debug version this is always -1 */
465
ulint* ph_size,/*!< out: physical size of the heap,
466
if a NULL pointer is passed as this
467
argument, it is ignored */
468
ulint* n_blocks) /*!< out: number of blocks in the heap,
469
if a NULL pointer is passed as this
470
argument, it is ignored */
474
ulint block_count = 0;
476
#ifdef UNIV_MEM_DEBUG
483
/* Pessimistically, we set the parameters to error values */
484
if (us_size != NULL) {
487
if (ph_size != NULL) {
490
if (n_blocks != NULL) {
497
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
502
fputs("Memory heap:", stderr);
505
while (block != NULL) {
506
phys_len += mem_block_get_len(block);
508
if ((block->type == MEM_HEAP_BUFFER)
509
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
512
"InnoDB: Error: mem block %p"
513
" length %lu > UNIV_PAGE_SIZE\n",
515
(ulong) mem_block_get_len(block));
521
#ifdef UNIV_MEM_DEBUG
522
/* We can trace the fields of the block only in the debug
525
fprintf(stderr, " Block %ld:", block_count);
528
field = (byte*)block + mem_block_get_start(block);
530
if (top && (field == top)) {
535
while (field < (byte*)block + mem_block_get_free(block)) {
537
/* Calculate the pointer to the storage
538
which was given to the user */
540
user_field = field + MEM_FIELD_HEADER_SIZE;
542
len = mem_field_header_get_len(user_field);
545
ut_print_buf(stderr, user_field, len);
550
check_field = mem_field_header_get_check(user_field);
553
!= mem_field_trailer_get_check(user_field)) {
557
"InnoDB: Error: block %lx mem"
558
" field %lx len %lu\n"
559
"InnoDB: header check field is"
560
" %lx but trailer %lx\n",
562
(ulint)field, len, check_field,
563
mem_field_trailer_get_check(
569
/* Move to next field */
570
field = field + MEM_SPACE_NEEDED(len);
572
if (top && (field == top)) {
579
/* At the end check that we have arrived to the first free
582
if (field != (byte*)block + mem_block_get_free(block)) {
586
"InnoDB: Error: block %lx end of"
588
"InnoDB: but block free at %lx\n",
589
(ulint)block, (ulint)field,
591
+ mem_block_get_free(block)));
598
block = UT_LIST_GET_NEXT(list, block);
601
#ifdef UNIV_MEM_DEBUG
604
if (us_size != NULL) {
605
*us_size = total_len;
607
if (ph_size != NULL) {
610
if (n_blocks != NULL) {
611
*n_blocks = block_count;
616
/**************************************************************//**
617
Prints the contents of a memory heap. */
622
mem_heap_t* heap) /*!< in: memory heap */
629
ut_ad(mem_heap_check(heap));
631
mem_heap_validate_or_print(heap, NULL, TRUE, &error,
632
&us_size, &phys_size, &n_blocks);
634
"\nheap type: %lu; size: user size %lu;"
635
" physical size %lu; blocks %lu.\n",
636
(ulong) heap->type, (ulong) us_size,
637
(ulong) phys_size, (ulong) n_blocks);
641
/**************************************************************//**
642
Validates the contents of a memory heap.
643
@return TRUE if ok */
648
mem_heap_t* heap) /*!< in: memory heap */
655
ut_ad(mem_heap_check(heap));
657
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
658
&phys_size, &n_blocks);
660
mem_heap_print(heap);
667
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
670
/**************************************************************//**
671
Checks that an object is a memory heap (or a block of it).
672
@return TRUE if ok */
677
mem_heap_t* heap) /*!< in: memory heap */
679
ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
683
#endif /* UNIV_DEBUG */
685
#ifdef UNIV_MEM_DEBUG
686
/*****************************************************************//**
687
TRUE if no memory is currently allocated.
688
@return TRUE if no heaps exist */
694
mem_hash_node_t* node;
695
ulint heap_count = 0;
700
mutex_enter(&mem_hash_mutex);
702
for (i = 0; i < MEM_HASH_SIZE; i++) {
704
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
705
while (node != NULL) {
707
node = UT_LIST_GET_NEXT(list, node);
711
mutex_exit(&mem_hash_mutex);
713
if (heap_count == 0) {
714
# ifndef UNIV_HOTBACKUP
715
ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
716
# endif /* !UNIV_HOTBACKUP */
724
/*****************************************************************//**
725
Validates the dynamic memory allocation system.
726
@return TRUE if error */
729
mem_validate_no_assert(void)
730
/*========================*/
732
mem_hash_node_t* node;
736
ulint total_allocated_mem = 0;
741
# ifndef UNIV_HOTBACKUP
742
mem_pool_validate(mem_comm_pool);
743
# endif /* !UNIV_HOTBACKUP */
745
mutex_enter(&mem_hash_mutex);
747
for (i = 0; i < MEM_HASH_SIZE; i++) {
749
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
751
while (node != NULL) {
754
mem_heap_validate_or_print(node->heap, NULL,
757
&ph_size, &n_blocks);
761
"\nERROR!!!!!!!!!!!!!!!!!!!"
762
"!!!!!!!!!!!!!!!!!!!!!!!\n\n"
763
"Inconsistency in memory heap"
764
" or buffer created\n"
766
node->file_name, node->line);
768
mutex_exit(&mem_hash_mutex);
773
total_allocated_mem += allocated_mem;
774
node = UT_LIST_GET_NEXT(list, node);
778
if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
782
if (mem_total_allocated_memory < mem_current_allocated_memory) {
786
if (mem_max_allocated_memory > mem_total_allocated_memory) {
790
if (mem_n_created_heaps < n_heaps) {
794
mutex_exit(&mem_hash_mutex);
799
/************************************************************//**
800
Validates the dynamic memory
801
@return TRUE if ok */
807
ut_a(!mem_validate_no_assert());
811
#endif /* UNIV_MEM_DEBUG */
813
/************************************************************//**
814
Tries to find neigboring memory allocation blocks and dumps to stderr
815
the neighborhood of a given pointer. */
818
mem_analyze_corruption(
819
/*===================*/
820
void* ptr) /*!< in: pointer to place of possible corruption */
826
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
827
ut_print_buf(stderr, (byte*)ptr - 250, 500);
829
fputs("\nInnoDB: Scanning backward trying to find"
830
" previous allocated mem blocks\n", stderr);
835
for (i = 0; i < 10; i++) {
837
if (((ulint)p) % 4 == 0) {
839
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
841
"Mem block at - %lu,"
842
" file %s, line %lu\n",
852
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
854
"Freed mem block at - %lu,"
855
" file %s, line %lu\n",
875
"InnoDB: Scanning forward trying to find next"
876
" allocated mem blocks\n");
881
for (i = 0; i < 10; i++) {
883
if (((ulint)p) % 4 == 0) {
885
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
887
"Mem block at + %lu, file %s,"
898
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
900
"Freed mem block at + %lu,"
901
" file %s, line %lu\n",
921
#ifndef UNIV_HOTBACKUP
922
/*****************************************************************//**
923
Prints information of dynamic memory usage and currently allocated
924
memory heaps or buffers. Can only be used in the debug version. */
929
ibool print_all) /*!< in: if TRUE, all heaps are printed,
930
else only the heaps allocated after the
931
previous call of this function */
933
#ifdef UNIV_MEM_DEBUG
934
mem_hash_node_t* node;
938
ulint total_allocated_mem = 0;
944
/* outfile = fopen("ibdebug", "a"); */
948
fprintf(outfile, "\n");
950
"________________________________________________________\n");
951
fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
953
#ifndef UNIV_MEM_DEBUG
955
UT_NOT_USED(print_all);
957
mem_pool_print_info(outfile, mem_comm_pool);
960
"Sorry, non-debug version cannot give more memory info\n");
962
/* fclose(outfile); */
966
mutex_enter(&mem_hash_mutex);
968
fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
971
fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
974
node = UT_LIST_GET_FIRST(mem_all_list_base);
976
while (node != NULL) {
979
if (!print_all && node->nth_heap < mem_last_print_info) {
984
mem_heap_validate_or_print(node->heap, NULL,
985
FALSE, &error, &allocated_mem,
986
&ph_size, &n_blocks);
987
total_allocated_mem += allocated_mem;
990
"%lu: file %s line %lu of size %lu phys.size %lu"
991
" with %lu blocks, type %lu\n",
992
node->nth_heap, node->file_name, node->line,
993
allocated_mem, ph_size, n_blocks,
996
node = UT_LIST_GET_NEXT(all_list, node);
999
fprintf(outfile, "\n");
1001
fprintf(outfile, "Current allocated memory : %lu\n",
1002
mem_current_allocated_memory);
1003
fprintf(outfile, "Current allocated heaps and buffers : %lu\n",
1005
fprintf(outfile, "Cumulative allocated memory : %lu\n",
1006
mem_total_allocated_memory);
1007
fprintf(outfile, "Maximum allocated memory : %lu\n",
1008
mem_max_allocated_memory);
1009
fprintf(outfile, "Cumulative created heaps and buffers : %lu\n",
1010
mem_n_created_heaps);
1011
fprintf(outfile, "Cumulative number of allocations : %lu\n",
1014
mem_last_print_info = mem_n_created_heaps;
1016
mutex_exit(&mem_hash_mutex);
1018
mem_pool_print_info(outfile, mem_comm_pool);
1020
/* mem_validate(); */
1022
/* fclose(outfile); */
1026
/*****************************************************************//**
1027
Prints information of dynamic memory usage and currently allocated memory
1028
heaps or buffers. Can only be used in the debug version. */
1031
mem_print_info(void)
1032
/*================*/
1034
mem_print_info_low(TRUE);
1037
/*****************************************************************//**
1038
Prints information of dynamic memory usage and currently allocated memory
1039
heaps or buffers since the last ..._print_info or..._print_new_info. */
1042
mem_print_new_info(void)
1043
/*====================*/
1045
mem_print_info_low(FALSE);
1047
#endif /* !UNIV_HOTBACKUP */