~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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