~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
}