~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/mem/mem0dbg.cc

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
 
4
 
 
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.
 
8
 
 
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.
 
12
 
 
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
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/********************************************************************//**
 
20
@file mem/mem0dbg.c
 
21
The memory management: the debug code. This is not a compilation module,
 
22
but is included in mem0mem.* !
 
23
 
 
24
Created 6/9/1994 Heikki Tuuri
 
25
*************************************************************************/
 
26
 
 
27
#ifdef UNIV_MEM_DEBUG
 
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
 
31
variables below. */
 
32
UNIV_INTERN mutex_t             mem_hash_mutex;
 
33
 
 
34
#ifdef UNIV_PFS_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 */
 
38
 
 
39
# endif /* !UNIV_HOTBACKUP */
 
40
 
 
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. */
 
44
 
 
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 */
 
54
 
 
55
/* Size of the hash table for memory management tracking */
 
56
#define MEM_HASH_SIZE   997
 
57
 
 
58
/* The node of the list containing currently allocated memory heaps */
 
59
 
 
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 */
 
70
};
 
71
 
 
72
typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t;
 
73
 
 
74
/* The hash table of allocated heaps */
 
75
static mem_hash_cell_t          mem_hash_table[MEM_HASH_SIZE];
 
76
 
 
77
/* The base node of the list of all allocated heaps */
 
78
static mem_hash_cell_t          mem_all_list_base;
 
79
 
 
80
 
 
81
 
 
82
UNIV_INLINE
 
83
mem_hash_cell_t*
 
84
mem_hash_get_nth_cell(ulint i);
 
85
 
 
86
/* Accessor function for the hash table. Returns a pointer to the
 
87
table cell. */
 
88
UNIV_INLINE
 
89
mem_hash_cell_t*
 
90
mem_hash_get_nth_cell(ulint i)
 
91
{
 
92
        ut_a(i < MEM_HASH_SIZE);
 
93
 
 
94
        return(&(mem_hash_table[i]));
 
95
}
 
96
 
 
97
/* Accessor functions for a memory field in the debug version */
 
98
UNIV_INTERN
 
99
void
 
100
mem_field_header_set_len(byte* field, ulint len)
 
101
{
 
102
        mach_write_to_4(field - 2 * sizeof(ulint), len);
 
103
}
 
104
 
 
105
UNIV_INTERN
 
106
ulint
 
107
mem_field_header_get_len(byte* field)
 
108
{
 
109
        return(mach_read_from_4(field - 2 * sizeof(ulint)));
 
110
}
 
111
 
 
112
UNIV_INTERN
 
113
void
 
114
mem_field_header_set_check(byte* field, ulint check)
 
115
{
 
116
        mach_write_to_4(field - sizeof(ulint), check);
 
117
}
 
118
 
 
119
UNIV_INTERN
 
120
ulint
 
121
mem_field_header_get_check(byte* field)
 
122
{
 
123
        return(mach_read_from_4(field - sizeof(ulint)));
 
124
}
 
125
 
 
126
UNIV_INTERN
 
127
void
 
128
mem_field_trailer_set_check(byte* field, ulint check)
 
129
{
 
130
        mach_write_to_4(field + mem_field_header_get_len(field), check);
 
131
}
 
132
 
 
133
UNIV_INTERN
 
134
ulint
 
135
mem_field_trailer_get_check(byte* field)
 
136
{
 
137
        return(mach_read_from_4(field
 
138
                                + mem_field_header_get_len(field)));
 
139
}
 
140
#endif /* UNIV_MEM_DEBUG */
 
141
 
 
142
#ifndef UNIV_HOTBACKUP
 
143
/******************************************************************//**
 
144
Initializes the memory system. */
 
145
UNIV_INTERN
 
146
void
 
147
mem_init(
 
148
/*=====*/
 
149
        ulint   size)   /*!< in: common pool size in bytes */
 
150
{
 
151
#ifdef UNIV_MEM_DEBUG
 
152
 
 
153
        ulint   i;
 
154
 
 
155
        /* Initialize the hash table */
 
156
        ut_a(FALSE == mem_hash_initialized);
 
157
 
 
158
        mutex_create(mem_hash_mutex_key, &mem_hash_mutex, SYNC_MEM_HASH);
 
159
 
 
160
        for (i = 0; i < MEM_HASH_SIZE; i++) {
 
161
                UT_LIST_INIT(*mem_hash_get_nth_cell(i));
 
162
        }
 
163
 
 
164
        UT_LIST_INIT(mem_all_list_base);
 
165
 
 
166
        mem_hash_initialized = TRUE;
 
167
#endif
 
168
 
 
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. */
 
174
                size = 1;
 
175
        }
 
176
 
 
177
        mem_comm_pool = mem_pool_create(size);
 
178
}
 
179
 
 
180
/******************************************************************//**
 
181
Closes the memory system. */
 
182
UNIV_INTERN
 
183
void
 
184
mem_close(void)
 
185
/*===========*/
 
186
{
 
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 */
 
193
}
 
194
#endif /* !UNIV_HOTBACKUP */
 
195
 
 
196
#ifdef UNIV_MEM_DEBUG
 
197
/******************************************************************//**
 
198
Initializes an allocated memory field in the debug version. */
 
199
UNIV_INTERN
 
200
void
 
201
mem_field_init(
 
202
/*===========*/
 
203
        byte*   buf,    /*!< in: memory field */
 
204
        ulint   n)      /*!< in: how many bytes the user requested */
 
205
{
 
206
        ulint   rnd;
 
207
        byte*   usr_buf;
 
208
 
 
209
        usr_buf = buf + MEM_FIELD_HEADER_SIZE;
 
210
 
 
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. */
 
216
 
 
217
        mem_field_header_set_len(usr_buf, n);
 
218
 
 
219
        rnd = ut_rnd_gen_ulint();
 
220
 
 
221
        mem_field_header_set_check(usr_buf, rnd);
 
222
        mem_field_trailer_set_check(usr_buf, rnd);
 
223
 
 
224
        /* Update the memory allocation information */
 
225
 
 
226
        mutex_enter(&mem_hash_mutex);
 
227
 
 
228
        mem_total_allocated_memory += n;
 
229
        mem_current_allocated_memory += n;
 
230
        mem_n_allocations++;
 
231
 
 
232
        if (mem_current_allocated_memory > mem_max_allocated_memory) {
 
233
                mem_max_allocated_memory = mem_current_allocated_memory;
 
234
        }
 
235
 
 
236
        mutex_exit(&mem_hash_mutex);
 
237
 
 
238
        /* In the debug version set the buffer to a random
 
239
        combination of 0xBA and 0xBE */
 
240
 
 
241
        mem_init_buf(usr_buf, n);
 
242
}
 
243
 
 
244
/******************************************************************//**
 
245
Erases an allocated memory field in the debug version. */
 
246
UNIV_INTERN
 
247
void
 
248
mem_field_erase(
 
249
/*============*/
 
250
        byte*   buf,    /*!< in: memory field */
 
251
        ulint   /*n __attribute__((unused))*/)
 
252
                        /*!< in: how many bytes the user requested */
 
253
{
 
254
        byte*   usr_buf;
 
255
 
 
256
        usr_buf = buf + MEM_FIELD_HEADER_SIZE;
 
257
 
 
258
        mutex_enter(&mem_hash_mutex);
 
259
        mem_current_allocated_memory    -= n;
 
260
        mutex_exit(&mem_hash_mutex);
 
261
 
 
262
        /* Check that the field lengths agree */
 
263
        ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
 
264
 
 
265
        /* In the debug version, set the freed space to a random
 
266
        combination of 0xDE and 0xAD */
 
267
 
 
268
        mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
 
269
}
 
270
 
 
271
/***************************************************************//**
 
272
Initializes a buffer to a random combination of hex BA and BE.
 
273
Used to initialize allocated memory. */
 
274
UNIV_INTERN
 
275
void
 
276
mem_init_buf(
 
277
/*=========*/
 
278
        byte*   buf,    /*!< in: pointer to buffer */
 
279
        ulint    n)     /*!< in: length of buffer */
 
280
{
 
281
        byte*   ptr;
 
282
 
 
283
        UNIV_MEM_ASSERT_W(buf, n);
 
284
 
 
285
        for (ptr = buf; ptr < buf + n; ptr++) {
 
286
 
 
287
                if (ut_rnd_gen_ibool()) {
 
288
                        *ptr = 0xBA;
 
289
                } else {
 
290
                        *ptr = 0xBE;
 
291
                }
 
292
        }
 
293
 
 
294
        UNIV_MEM_INVALID(buf, n);
 
295
}
 
296
 
 
297
/***************************************************************//**
 
298
Initializes a buffer to a random combination of hex DE and AD.
 
299
Used to erase freed memory. */
 
300
UNIV_INTERN
 
301
void
 
302
mem_erase_buf(
 
303
/*==========*/
 
304
        byte*   buf,    /*!< in: pointer to buffer */
 
305
        ulint   n)      /*!< in: length of buffer */
 
306
{
 
307
        byte*   ptr;
 
308
 
 
309
        UNIV_MEM_ASSERT_W(buf, n);
 
310
 
 
311
        for (ptr = buf; ptr < buf + n; ptr++) {
 
312
                if (ut_rnd_gen_ibool()) {
 
313
                        *ptr = 0xDE;
 
314
                } else {
 
315
                        *ptr = 0xAD;
 
316
                }
 
317
        }
 
318
 
 
319
        UNIV_MEM_FREE(buf, n);
 
320
}
 
321
 
 
322
/***************************************************************//**
 
323
Inserts a created memory heap to the hash table of current allocated
 
324
memory heaps. */
 
325
UNIV_INTERN
 
326
void
 
327
mem_hash_insert(
 
328
/*============*/
 
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 */
 
332
{
 
333
        mem_hash_node_t*        new_node;
 
334
        ulint                   cell_no ;
 
335
 
 
336
        ut_ad(mem_heap_check(heap));
 
337
 
 
338
        mutex_enter(&mem_hash_mutex);
 
339
 
 
340
        cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
 
341
 
 
342
        /* Allocate a new node to the list */
 
343
        new_node = ut_malloc(sizeof(mem_hash_node_t));
 
344
 
 
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;
 
349
 
 
350
        /* Insert into lists */
 
351
        UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
 
352
 
 
353
        UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
 
354
 
 
355
        mem_n_created_heaps++;
 
356
 
 
357
        mutex_exit(&mem_hash_mutex);
 
358
}
 
359
 
 
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. */
 
368
UNIV_INTERN
 
369
void
 
370
mem_hash_remove(
 
371
/*============*/
 
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 */
 
375
{
 
376
        mem_hash_node_t*        node;
 
377
        ulint                   cell_no;
 
378
        ibool                   error;
 
379
        ulint                   size;
 
380
 
 
381
        ut_ad(mem_heap_check(heap));
 
382
 
 
383
        mutex_enter(&mem_hash_mutex);
 
384
 
 
385
        cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
 
386
 
 
387
        /* Look for the heap in the hash table list */
 
388
        node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
 
389
 
 
390
        while (node != NULL) {
 
391
                if (node->heap == heap) {
 
392
 
 
393
                        break;
 
394
                }
 
395
 
 
396
                node = UT_LIST_GET_NEXT(list, node);
 
397
        }
 
398
 
 
399
        if (node == NULL) {
 
400
                fprintf(stderr,
 
401
                        "Memory heap or buffer freed in %s line %lu"
 
402
                        " did not exist.\n",
 
403
                        file_name, (ulong) line);
 
404
                ut_error;
 
405
        }
 
406
 
 
407
        /* Remove from lists */
 
408
        UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
 
409
 
 
410
        UT_LIST_REMOVE(all_list, mem_all_list_base, node);
 
411
 
 
412
        /* Validate the heap which will be freed */
 
413
        mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
 
414
                                   NULL, NULL);
 
415
        if (error) {
 
416
                fprintf(stderr,
 
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,
 
427
                                           &size, NULL, NULL);
 
428
                ut_error;
 
429
        }
 
430
 
 
431
        /* Free the memory occupied by the node struct */
 
432
        ut_free(node);
 
433
 
 
434
        mem_current_allocated_memory -= size;
 
435
 
 
436
        mutex_exit(&mem_hash_mutex);
 
437
}
 
438
#endif /* UNIV_MEM_DEBUG */
 
439
 
 
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
 
446
of blocks. */
 
447
UNIV_INTERN
 
448
void
 
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
 
458
                                the debug version */
 
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 */
 
471
{
 
472
        mem_block_t*    block;
 
473
        ulint           total_len       = 0;
 
474
        ulint           block_count     = 0;
 
475
        ulint           phys_len        = 0;
 
476
#ifdef UNIV_MEM_DEBUG
 
477
        ulint           len;
 
478
        byte*           field;
 
479
        byte*           user_field;
 
480
        ulint           check_field;
 
481
#endif
 
482
 
 
483
        /* Pessimistically, we set the parameters to error values */
 
484
        if (us_size != NULL) {
 
485
                *us_size = 0;
 
486
        }
 
487
        if (ph_size != NULL) {
 
488
                *ph_size = 0;
 
489
        }
 
490
        if (n_blocks != NULL) {
 
491
                *n_blocks = 0;
 
492
        }
 
493
        *error = TRUE;
 
494
 
 
495
        block = heap;
 
496
 
 
497
        if (block->magic_n != MEM_BLOCK_MAGIC_N) {
 
498
                return;
 
499
        }
 
500
 
 
501
        if (print) {
 
502
                fputs("Memory heap:", stderr);
 
503
        }
 
504
 
 
505
        while (block != NULL) {
 
506
                phys_len += mem_block_get_len(block);
 
507
 
 
508
                if ((block->type == MEM_HEAP_BUFFER)
 
509
                    && (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
 
510
 
 
511
                        fprintf(stderr,
 
512
                                "InnoDB: Error: mem block %p"
 
513
                                " length %lu > UNIV_PAGE_SIZE\n",
 
514
                                (void*) block,
 
515
                                (ulong) mem_block_get_len(block));
 
516
                        /* error */
 
517
 
 
518
                        return;
 
519
                }
 
520
 
 
521
#ifdef UNIV_MEM_DEBUG
 
522
                /* We can trace the fields of the block only in the debug
 
523
                version */
 
524
                if (print) {
 
525
                        fprintf(stderr, " Block %ld:", block_count);
 
526
                }
 
527
 
 
528
                field = (byte*)block + mem_block_get_start(block);
 
529
 
 
530
                if (top && (field == top)) {
 
531
 
 
532
                        goto completed;
 
533
                }
 
534
 
 
535
                while (field < (byte*)block + mem_block_get_free(block)) {
 
536
 
 
537
                        /* Calculate the pointer to the storage
 
538
                        which was given to the user */
 
539
 
 
540
                        user_field = field + MEM_FIELD_HEADER_SIZE;
 
541
 
 
542
                        len = mem_field_header_get_len(user_field);
 
543
 
 
544
                        if (print) {
 
545
                                ut_print_buf(stderr, user_field, len);
 
546
                                putc('\n', stderr);
 
547
                        }
 
548
 
 
549
                        total_len += len;
 
550
                        check_field = mem_field_header_get_check(user_field);
 
551
 
 
552
                        if (check_field
 
553
                            != mem_field_trailer_get_check(user_field)) {
 
554
                                /* error */
 
555
 
 
556
                                fprintf(stderr,
 
557
                                        "InnoDB: Error: block %lx mem"
 
558
                                        " field %lx len %lu\n"
 
559
                                        "InnoDB: header check field is"
 
560
                                        " %lx but trailer %lx\n",
 
561
                                        (ulint)block,
 
562
                                        (ulint)field, len, check_field,
 
563
                                        mem_field_trailer_get_check(
 
564
                                                user_field));
 
565
 
 
566
                                return;
 
567
                        }
 
568
 
 
569
                        /* Move to next field */
 
570
                        field = field + MEM_SPACE_NEEDED(len);
 
571
 
 
572
                        if (top && (field == top)) {
 
573
 
 
574
                                goto completed;
 
575
                        }
 
576
 
 
577
                }
 
578
 
 
579
                /* At the end check that we have arrived to the first free
 
580
                position */
 
581
 
 
582
                if (field != (byte*)block + mem_block_get_free(block)) {
 
583
                        /* error */
 
584
 
 
585
                        fprintf(stderr,
 
586
                                "InnoDB: Error: block %lx end of"
 
587
                                " mem fields %lx\n"
 
588
                                "InnoDB: but block free at %lx\n",
 
589
                                (ulint)block, (ulint)field,
 
590
                                (ulint)((byte*)block
 
591
                                        + mem_block_get_free(block)));
 
592
 
 
593
                        return;
 
594
                }
 
595
 
 
596
#endif
 
597
 
 
598
                block = UT_LIST_GET_NEXT(list, block);
 
599
                block_count++;
 
600
        }
 
601
#ifdef UNIV_MEM_DEBUG
 
602
completed:
 
603
#endif
 
604
        if (us_size != NULL) {
 
605
                *us_size = total_len;
 
606
        }
 
607
        if (ph_size != NULL) {
 
608
                *ph_size = phys_len;
 
609
        }
 
610
        if (n_blocks != NULL) {
 
611
                *n_blocks = block_count;
 
612
        }
 
613
        *error = FALSE;
 
614
}
 
615
 
 
616
/**************************************************************//**
 
617
Prints the contents of a memory heap. */
 
618
static
 
619
void
 
620
mem_heap_print(
 
621
/*===========*/
 
622
        mem_heap_t*     heap)   /*!< in: memory heap */
 
623
{
 
624
        ibool   error;
 
625
        ulint   us_size;
 
626
        ulint   phys_size;
 
627
        ulint   n_blocks;
 
628
 
 
629
        ut_ad(mem_heap_check(heap));
 
630
 
 
631
        mem_heap_validate_or_print(heap, NULL, TRUE, &error,
 
632
                                   &us_size, &phys_size, &n_blocks);
 
633
        fprintf(stderr,
 
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);
 
638
        ut_a(!error);
 
639
}
 
640
 
 
641
/**************************************************************//**
 
642
Validates the contents of a memory heap.
 
643
@return TRUE if ok */
 
644
UNIV_INTERN
 
645
ibool
 
646
mem_heap_validate(
 
647
/*==============*/
 
648
        mem_heap_t*     heap)   /*!< in: memory heap */
 
649
{
 
650
        ibool   error;
 
651
        ulint   us_size;
 
652
        ulint   phys_size;
 
653
        ulint   n_blocks;
 
654
 
 
655
        ut_ad(mem_heap_check(heap));
 
656
 
 
657
        mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
 
658
                                   &phys_size, &n_blocks);
 
659
        if (error) {
 
660
                mem_heap_print(heap);
 
661
        }
 
662
 
 
663
        ut_a(!error);
 
664
 
 
665
        return(TRUE);
 
666
}
 
667
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
 
668
 
 
669
#ifdef UNIV_DEBUG
 
670
/**************************************************************//**
 
671
Checks that an object is a memory heap (or a block of it).
 
672
@return TRUE if ok */
 
673
UNIV_INTERN
 
674
ibool
 
675
mem_heap_check(
 
676
/*===========*/
 
677
        mem_heap_t*     heap)   /*!< in: memory heap */
 
678
{
 
679
        ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
 
680
 
 
681
        return(TRUE);
 
682
}
 
683
#endif /* UNIV_DEBUG */
 
684
 
 
685
#ifdef UNIV_MEM_DEBUG
 
686
/*****************************************************************//**
 
687
TRUE if no memory is currently allocated.
 
688
@return TRUE if no heaps exist */
 
689
UNIV_INTERN
 
690
ibool
 
691
mem_all_freed(void)
 
692
/*===============*/
 
693
{
 
694
        mem_hash_node_t*        node;
 
695
        ulint                   heap_count      = 0;
 
696
        ulint                   i;
 
697
 
 
698
        mem_validate();
 
699
 
 
700
        mutex_enter(&mem_hash_mutex);
 
701
 
 
702
        for (i = 0; i < MEM_HASH_SIZE; i++) {
 
703
 
 
704
                node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
 
705
                while (node != NULL) {
 
706
                        heap_count++;
 
707
                        node = UT_LIST_GET_NEXT(list, node);
 
708
                }
 
709
        }
 
710
 
 
711
        mutex_exit(&mem_hash_mutex);
 
712
 
 
713
        if (heap_count == 0) {
 
714
# ifndef UNIV_HOTBACKUP
 
715
                ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
 
716
# endif /* !UNIV_HOTBACKUP */
 
717
 
 
718
                return(TRUE);
 
719
        } else {
 
720
                return(FALSE);
 
721
        }
 
722
}
 
723
 
 
724
/*****************************************************************//**
 
725
Validates the dynamic memory allocation system.
 
726
@return TRUE if error */
 
727
UNIV_INTERN
 
728
ibool
 
729
mem_validate_no_assert(void)
 
730
/*========================*/
 
731
{
 
732
        mem_hash_node_t*        node;
 
733
        ulint                   n_heaps                 = 0;
 
734
        ulint                   allocated_mem;
 
735
        ulint                   ph_size;
 
736
        ulint                   total_allocated_mem     = 0;
 
737
        ibool                   error                   = FALSE;
 
738
        ulint                   n_blocks;
 
739
        ulint                   i;
 
740
 
 
741
# ifndef UNIV_HOTBACKUP
 
742
        mem_pool_validate(mem_comm_pool);
 
743
# endif /* !UNIV_HOTBACKUP */
 
744
 
 
745
        mutex_enter(&mem_hash_mutex);
 
746
 
 
747
        for (i = 0; i < MEM_HASH_SIZE; i++) {
 
748
 
 
749
                node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
 
750
 
 
751
                while (node != NULL) {
 
752
                        n_heaps++;
 
753
 
 
754
                        mem_heap_validate_or_print(node->heap, NULL,
 
755
                                                   FALSE, &error,
 
756
                                                   &allocated_mem,
 
757
                                                   &ph_size, &n_blocks);
 
758
 
 
759
                        if (error) {
 
760
                                fprintf(stderr,
 
761
                                        "\nERROR!!!!!!!!!!!!!!!!!!!"
 
762
                                        "!!!!!!!!!!!!!!!!!!!!!!!\n\n"
 
763
                                        "Inconsistency in memory heap"
 
764
                                        " or buffer created\n"
 
765
                                        "in %s line %lu.\n",
 
766
                                        node->file_name, node->line);
 
767
 
 
768
                                mutex_exit(&mem_hash_mutex);
 
769
 
 
770
                                return(TRUE);
 
771
                        }
 
772
 
 
773
                        total_allocated_mem += allocated_mem;
 
774
                        node = UT_LIST_GET_NEXT(list, node);
 
775
                }
 
776
        }
 
777
 
 
778
        if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
 
779
                error = TRUE;
 
780
        }
 
781
 
 
782
        if (mem_total_allocated_memory < mem_current_allocated_memory) {
 
783
                error = TRUE;
 
784
        }
 
785
 
 
786
        if (mem_max_allocated_memory > mem_total_allocated_memory) {
 
787
                error = TRUE;
 
788
        }
 
789
 
 
790
        if (mem_n_created_heaps < n_heaps) {
 
791
                error = TRUE;
 
792
        }
 
793
 
 
794
        mutex_exit(&mem_hash_mutex);
 
795
 
 
796
        return(error);
 
797
}
 
798
 
 
799
/************************************************************//**
 
800
Validates the dynamic memory
 
801
@return TRUE if ok */
 
802
UNIV_INTERN
 
803
ibool
 
804
mem_validate(void)
 
805
/*==============*/
 
806
{
 
807
        ut_a(!mem_validate_no_assert());
 
808
 
 
809
        return(TRUE);
 
810
}
 
811
#endif /* UNIV_MEM_DEBUG */
 
812
 
 
813
/************************************************************//**
 
814
Tries to find neigboring memory allocation blocks and dumps to stderr
 
815
the neighborhood of a given pointer. */
 
816
UNIV_INTERN
 
817
void
 
818
mem_analyze_corruption(
 
819
/*===================*/
 
820
        void*   ptr)    /*!< in: pointer to place of possible corruption */
 
821
{
 
822
        byte*   p;
 
823
        ulint   i;
 
824
        ulint   dist;
 
825
 
 
826
        fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
 
827
        ut_print_buf(stderr, (byte*)ptr - 250, 500);
 
828
 
 
829
        fputs("\nInnoDB: Scanning backward trying to find"
 
830
              " previous allocated mem blocks\n", stderr);
 
831
 
 
832
        p = (byte*)ptr;
 
833
        dist = 0;
 
834
 
 
835
        for (i = 0; i < 10; i++) {
 
836
                for (;;) {
 
837
                        if (((ulint)p) % 4 == 0) {
 
838
 
 
839
                                if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
 
840
                                        fprintf(stderr,
 
841
                                                "Mem block at - %lu,"
 
842
                                                " file %s, line %lu\n",
 
843
                                                (ulong) dist,
 
844
                                                (p + sizeof(ulint)),
 
845
                                                (ulong)
 
846
                                                (*(ulint*)(p + 8
 
847
                                                           + sizeof(ulint))));
 
848
 
 
849
                                        break;
 
850
                                }
 
851
 
 
852
                                if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
 
853
                                        fprintf(stderr,
 
854
                                                "Freed mem block at - %lu,"
 
855
                                                " file %s, line %lu\n",
 
856
                                                (ulong) dist,
 
857
                                                (p + sizeof(ulint)),
 
858
                                                (ulong)
 
859
                                                (*(ulint*)(p + 8
 
860
                                                           + sizeof(ulint))));
 
861
 
 
862
                                        break;
 
863
                                }
 
864
                        }
 
865
 
 
866
                        p--;
 
867
                        dist++;
 
868
                }
 
869
 
 
870
                p--;
 
871
                dist++;
 
872
        }
 
873
 
 
874
        fprintf(stderr,
 
875
                "InnoDB: Scanning forward trying to find next"
 
876
                " allocated mem blocks\n");
 
877
 
 
878
        p = (byte*)ptr;
 
879
        dist = 0;
 
880
 
 
881
        for (i = 0; i < 10; i++) {
 
882
                for (;;) {
 
883
                        if (((ulint)p) % 4 == 0) {
 
884
 
 
885
                                if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
 
886
                                        fprintf(stderr,
 
887
                                                "Mem block at + %lu, file %s,"
 
888
                                                " line %lu\n",
 
889
                                                (ulong) dist,
 
890
                                                (p + sizeof(ulint)),
 
891
                                                (ulong)
 
892
                                                (*(ulint*)(p + 8
 
893
                                                           + sizeof(ulint))));
 
894
 
 
895
                                        break;
 
896
                                }
 
897
 
 
898
                                if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
 
899
                                        fprintf(stderr,
 
900
                                                "Freed mem block at + %lu,"
 
901
                                                " file %s, line %lu\n",
 
902
                                                (ulong) dist,
 
903
                                                (p + sizeof(ulint)),
 
904
                                                (ulong)
 
905
                                                (*(ulint*)(p + 8
 
906
                                                           + sizeof(ulint))));
 
907
 
 
908
                                        break;
 
909
                                }
 
910
                        }
 
911
 
 
912
                        p++;
 
913
                        dist++;
 
914
                }
 
915
 
 
916
                p++;
 
917
                dist++;
 
918
        }
 
919
}
 
920
 
 
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. */
 
925
static
 
926
void
 
927
mem_print_info_low(
 
928
/*===============*/
 
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 */
 
932
{
 
933
#ifdef UNIV_MEM_DEBUG
 
934
        mem_hash_node_t*        node;
 
935
        ulint                   n_heaps                 = 0;
 
936
        ulint                   allocated_mem;
 
937
        ulint                   ph_size;
 
938
        ulint                   total_allocated_mem     = 0;
 
939
        ibool                   error;
 
940
        ulint                   n_blocks;
 
941
#endif
 
942
        FILE*                   outfile;
 
943
 
 
944
        /* outfile = fopen("ibdebug", "a"); */
 
945
 
 
946
        outfile = stdout;
 
947
 
 
948
        fprintf(outfile, "\n");
 
949
        fprintf(outfile,
 
950
                "________________________________________________________\n");
 
951
        fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
 
952
 
 
953
#ifndef UNIV_MEM_DEBUG
 
954
 
 
955
        UT_NOT_USED(print_all);
 
956
 
 
957
        mem_pool_print_info(outfile, mem_comm_pool);
 
958
 
 
959
        fprintf(outfile,
 
960
                "Sorry, non-debug version cannot give more memory info\n");
 
961
 
 
962
        /* fclose(outfile); */
 
963
 
 
964
        return;
 
965
#else
 
966
        mutex_enter(&mem_hash_mutex);
 
967
 
 
968
        fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
 
969
 
 
970
        if (!print_all) {
 
971
                fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
 
972
        }
 
973
 
 
974
        node = UT_LIST_GET_FIRST(mem_all_list_base);
 
975
 
 
976
        while (node != NULL) {
 
977
                n_heaps++;
 
978
 
 
979
                if (!print_all && node->nth_heap < mem_last_print_info) {
 
980
 
 
981
                        goto next_heap;
 
982
                }
 
983
 
 
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;
 
988
 
 
989
                fprintf(outfile,
 
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,
 
994
                        (node->heap)->type);
 
995
next_heap:
 
996
                node = UT_LIST_GET_NEXT(all_list, node);
 
997
        }
 
998
 
 
999
        fprintf(outfile, "\n");
 
1000
 
 
1001
        fprintf(outfile, "Current allocated memory              : %lu\n",
 
1002
                mem_current_allocated_memory);
 
1003
        fprintf(outfile, "Current allocated heaps and buffers   : %lu\n",
 
1004
                n_heaps);
 
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",
 
1012
                mem_n_allocations);
 
1013
 
 
1014
        mem_last_print_info = mem_n_created_heaps;
 
1015
 
 
1016
        mutex_exit(&mem_hash_mutex);
 
1017
 
 
1018
        mem_pool_print_info(outfile, mem_comm_pool);
 
1019
 
 
1020
        /*      mem_validate(); */
 
1021
 
 
1022
        /*      fclose(outfile); */
 
1023
#endif
 
1024
}
 
1025
 
 
1026
/*****************************************************************//**
 
1027
Prints information of dynamic memory usage and currently allocated memory
 
1028
heaps or buffers. Can only be used in the debug version. */
 
1029
UNIV_INTERN
 
1030
void
 
1031
mem_print_info(void)
 
1032
/*================*/
 
1033
{
 
1034
        mem_print_info_low(TRUE);
 
1035
}
 
1036
 
 
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. */
 
1040
UNIV_INTERN
 
1041
void
 
1042
mem_print_new_info(void)
 
1043
/*====================*/
 
1044
{
 
1045
        mem_print_info_low(FALSE);
 
1046
}
 
1047
#endif /* !UNIV_HOTBACKUP */