~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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