~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-08-03 20:57:39 UTC
  • mfrom: (1680.6.4 rollup)
  • Revision ID: brian@gaz-20100803205739-7betgobkod41363k
Removes LOCK_system_variables_hash, one goto, drops internall new for std
new (so possible performance regression), fixes bug where Session was not
unlocked correctly.

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 */