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

« back to all changes in this revision

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