Drizzled Public API Documentation

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