Drizzled Public API Documentation

mem0dbg.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /********************************************************************/
00027 #ifdef UNIV_MEM_DEBUG
00028 # ifndef UNIV_HOTBACKUP
00029 /* The mutex which protects in the debug version the hash table
00030 containing the list of live memory heaps, and also the global
00031 variables below. */
00032 UNIV_INTERN mutex_t   mem_hash_mutex;
00033 
00034 #ifdef UNIV_PFS_MUTEX
00035 /* Key to register mem_hash_mutex with performance schema */
00036 UNIV_INTERN mysql_pfs_key_t mem_hash_mutex_key;
00037 #endif /* UNIV_PFS_MUTEX */
00038 
00039 # endif /* !UNIV_HOTBACKUP */
00040 
00041 /* The following variables contain information about the
00042 extent of memory allocations. Only used in the debug version.
00043 Protected by mem_hash_mutex above. */
00044 
00045 static ulint    mem_n_created_heaps   = 0;
00046 static ulint    mem_n_allocations   = 0;
00047 static ulint    mem_total_allocated_memory  = 0;
00048 UNIV_INTERN ulint mem_current_allocated_memory  = 0;
00049 static ulint    mem_max_allocated_memory  = 0;
00050 # ifndef UNIV_HOTBACKUP
00051 static ulint    mem_last_print_info   = 0;
00052 static ibool    mem_hash_initialized    = FALSE;
00053 # endif /* !UNIV_HOTBACKUP */
00054 
00055 /* Size of the hash table for memory management tracking */
00056 #define MEM_HASH_SIZE 997
00057 
00058 /* The node of the list containing currently allocated memory heaps */
00059 
00060 typedef struct mem_hash_node_struct mem_hash_node_t;
00061 struct mem_hash_node_struct {
00062   UT_LIST_NODE_T(mem_hash_node_t)
00063         list; 
00064   mem_heap_t*   heap; 
00065   const char*   file_name;/* file where heap was created*/
00066   ulint     line; 
00067   ulint     nth_heap;/* this is the nth heap created */
00068   UT_LIST_NODE_T(mem_hash_node_t)
00069         all_list;/* list of all created heaps */
00070 };
00071 
00072 typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t;
00073 
00074 /* The hash table of allocated heaps */
00075 static mem_hash_cell_t    mem_hash_table[MEM_HASH_SIZE];
00076 
00077 /* The base node of the list of all allocated heaps */
00078 static mem_hash_cell_t    mem_all_list_base;
00079 
00080 
00081 
00082 UNIV_INLINE
00083 mem_hash_cell_t*
00084 mem_hash_get_nth_cell(ulint i);
00085 
00086 /* Accessor function for the hash table. Returns a pointer to the
00087 table cell. */
00088 UNIV_INLINE
00089 mem_hash_cell_t*
00090 mem_hash_get_nth_cell(ulint i)
00091 {
00092   ut_a(i < MEM_HASH_SIZE);
00093 
00094   return(&(mem_hash_table[i]));
00095 }
00096 
00097 /* Accessor functions for a memory field in the debug version */
00098 UNIV_INTERN
00099 void
00100 mem_field_header_set_len(byte* field, ulint len)
00101 {
00102   mach_write_to_4(field - 2 * sizeof(ulint), len);
00103 }
00104 
00105 UNIV_INTERN
00106 ulint
00107 mem_field_header_get_len(byte* field)
00108 {
00109   return(mach_read_from_4(field - 2 * sizeof(ulint)));
00110 }
00111 
00112 UNIV_INTERN
00113 void
00114 mem_field_header_set_check(byte* field, ulint check)
00115 {
00116   mach_write_to_4(field - sizeof(ulint), check);
00117 }
00118 
00119 UNIV_INTERN
00120 ulint
00121 mem_field_header_get_check(byte* field)
00122 {
00123   return(mach_read_from_4(field - sizeof(ulint)));
00124 }
00125 
00126 UNIV_INTERN
00127 void
00128 mem_field_trailer_set_check(byte* field, ulint check)
00129 {
00130   mach_write_to_4(field + mem_field_header_get_len(field), check);
00131 }
00132 
00133 UNIV_INTERN
00134 ulint
00135 mem_field_trailer_get_check(byte* field)
00136 {
00137   return(mach_read_from_4(field
00138         + mem_field_header_get_len(field)));
00139 }
00140 #endif /* UNIV_MEM_DEBUG */
00141 
00142 #ifndef UNIV_HOTBACKUP
00143 /******************************************************************/
00145 UNIV_INTERN
00146 void
00147 mem_init(
00148 /*=====*/
00149   ulint size) 
00150 {
00151 #ifdef UNIV_MEM_DEBUG
00152 
00153   ulint i;
00154 
00155   /* Initialize the hash table */
00156   ut_a(FALSE == mem_hash_initialized);
00157 
00158   mutex_create(mem_hash_mutex_key, &mem_hash_mutex, SYNC_MEM_HASH);
00159 
00160   for (i = 0; i < MEM_HASH_SIZE; i++) {
00161     UT_LIST_INIT(*mem_hash_get_nth_cell(i));
00162   }
00163 
00164   UT_LIST_INIT(mem_all_list_base);
00165 
00166   mem_hash_initialized = TRUE;
00167 #endif
00168 
00169   if (UNIV_LIKELY(srv_use_sys_malloc)) {
00170     /* When innodb_use_sys_malloc is set, the
00171     mem_comm_pool won't be used for any allocations.  We
00172     create a dummy mem_comm_pool, because some statistics
00173     and debugging code relies on it being initialized. */
00174     size = 1;
00175   }
00176 
00177   mem_comm_pool = mem_pool_create(size);
00178 }
00179 
00180 /******************************************************************/
00182 UNIV_INTERN
00183 void
00184 mem_close(void)
00185 /*===========*/
00186 {
00187   mem_pool_free(mem_comm_pool);
00188   mem_comm_pool = NULL;
00189 #ifdef UNIV_MEM_DEBUG
00190   mutex_free(&mem_hash_mutex);
00191   mem_hash_initialized = FALSE;
00192 #endif /* UNIV_MEM_DEBUG */
00193 }
00194 #endif /* !UNIV_HOTBACKUP */
00195 
00196 #ifdef UNIV_MEM_DEBUG
00197 /******************************************************************/
00199 UNIV_INTERN
00200 void
00201 mem_field_init(
00202 /*===========*/
00203   byte* buf,  
00204   ulint n)  
00205 {
00206   ulint rnd;
00207   byte* usr_buf;
00208 
00209   usr_buf = buf + MEM_FIELD_HEADER_SIZE;
00210 
00211   /* In the debug version write the length field and the
00212   check fields to the start and the end of the allocated storage.
00213   The field header consists of a length field and
00214   a random number field, in this order. The field trailer contains
00215   the same random number as a check field. */
00216 
00217   mem_field_header_set_len(usr_buf, n);
00218 
00219   rnd = ut_rnd_gen_ulint();
00220 
00221   mem_field_header_set_check(usr_buf, rnd);
00222   mem_field_trailer_set_check(usr_buf, rnd);
00223 
00224   /* Update the memory allocation information */
00225 
00226   mutex_enter(&mem_hash_mutex);
00227 
00228   mem_total_allocated_memory += n;
00229   mem_current_allocated_memory += n;
00230   mem_n_allocations++;
00231 
00232   if (mem_current_allocated_memory > mem_max_allocated_memory) {
00233     mem_max_allocated_memory = mem_current_allocated_memory;
00234   }
00235 
00236   mutex_exit(&mem_hash_mutex);
00237 
00238   /* In the debug version set the buffer to a random
00239   combination of 0xBA and 0xBE */
00240 
00241   mem_init_buf(usr_buf, n);
00242 }
00243 
00244 /******************************************************************/
00246 UNIV_INTERN
00247 void
00248 mem_field_erase(
00249 /*============*/
00250   byte* buf,  
00251   ulint /*n __attribute__((unused))*/)
00253 {
00254   byte* usr_buf;
00255 
00256   usr_buf = buf + MEM_FIELD_HEADER_SIZE;
00257 
00258   mutex_enter(&mem_hash_mutex);
00259   mem_current_allocated_memory  -= n;
00260   mutex_exit(&mem_hash_mutex);
00261 
00262   /* Check that the field lengths agree */
00263   ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
00264 
00265   /* In the debug version, set the freed space to a random
00266   combination of 0xDE and 0xAD */
00267 
00268   mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
00269 }
00270 
00271 /***************************************************************/
00274 UNIV_INTERN
00275 void
00276 mem_init_buf(
00277 /*=========*/
00278   byte* buf,  
00279   ulint  n) 
00280 {
00281   byte* ptr;
00282 
00283   UNIV_MEM_ASSERT_W(buf, n);
00284 
00285   for (ptr = buf; ptr < buf + n; ptr++) {
00286 
00287     if (ut_rnd_gen_ibool()) {
00288       *ptr = 0xBA;
00289     } else {
00290       *ptr = 0xBE;
00291     }
00292   }
00293 
00294   UNIV_MEM_INVALID(buf, n);
00295 }
00296 
00297 /***************************************************************/
00300 UNIV_INTERN
00301 void
00302 mem_erase_buf(
00303 /*==========*/
00304   byte* buf,  
00305   ulint n)  
00306 {
00307   byte* ptr;
00308 
00309   UNIV_MEM_ASSERT_W(buf, n);
00310 
00311   for (ptr = buf; ptr < buf + n; ptr++) {
00312     if (ut_rnd_gen_ibool()) {
00313       *ptr = 0xDE;
00314     } else {
00315       *ptr = 0xAD;
00316     }
00317   }
00318 
00319   UNIV_MEM_FREE(buf, n);
00320 }
00321 
00322 /***************************************************************/
00325 UNIV_INTERN
00326 void
00327 mem_hash_insert(
00328 /*============*/
00329   mem_heap_t* heap,    
00330   const char* file_name, 
00331   ulint   line)    
00332 {
00333   mem_hash_node_t*  new_node;
00334   ulint     cell_no ;
00335 
00336   ut_ad(mem_heap_check(heap));
00337 
00338   mutex_enter(&mem_hash_mutex);
00339 
00340   cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
00341 
00342   /* Allocate a new node to the list */
00343   new_node = ut_malloc(sizeof(mem_hash_node_t));
00344 
00345   new_node->heap = heap;
00346   new_node->file_name = file_name;
00347   new_node->line = line;
00348   new_node->nth_heap = mem_n_created_heaps;
00349 
00350   /* Insert into lists */
00351   UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
00352 
00353   UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
00354 
00355   mem_n_created_heaps++;
00356 
00357   mutex_exit(&mem_hash_mutex);
00358 }
00359 
00360 /***************************************************************/
00368 UNIV_INTERN
00369 void
00370 mem_hash_remove(
00371 /*============*/
00372   mem_heap_t* heap,    
00373   const char* file_name, 
00374   ulint   line)    
00375 {
00376   mem_hash_node_t*  node;
00377   ulint     cell_no;
00378   ibool     error;
00379   ulint     size;
00380 
00381   ut_ad(mem_heap_check(heap));
00382 
00383   mutex_enter(&mem_hash_mutex);
00384 
00385   cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
00386 
00387   /* Look for the heap in the hash table list */
00388   node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
00389 
00390   while (node != NULL) {
00391     if (node->heap == heap) {
00392 
00393       break;
00394     }
00395 
00396     node = UT_LIST_GET_NEXT(list, node);
00397   }
00398 
00399   if (node == NULL) {
00400     fprintf(stderr,
00401       "Memory heap or buffer freed in %s line %lu"
00402       " did not exist.\n",
00403       file_name, (ulong) line);
00404     ut_error;
00405   }
00406 
00407   /* Remove from lists */
00408   UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
00409 
00410   UT_LIST_REMOVE(all_list, mem_all_list_base, node);
00411 
00412   /* Validate the heap which will be freed */
00413   mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
00414            NULL, NULL);
00415   if (error) {
00416     fprintf(stderr,
00417       "Inconsistency in memory heap or"
00418       " buffer n:o %lu created\n"
00419       "in %s line %lu and tried to free in %s line %lu.\n"
00420       "Hex dump of 400 bytes around memory heap"
00421       " first block start:\n",
00422       node->nth_heap, node->file_name, (ulong) node->line,
00423       file_name, (ulong) line);
00424     ut_print_buf(stderr, (byte*)node->heap - 200, 400);
00425     fputs("\nDump of the mem heap:\n", stderr);
00426     mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
00427              &size, NULL, NULL);
00428     ut_error;
00429   }
00430 
00431   /* Free the memory occupied by the node struct */
00432   ut_free(node);
00433 
00434   mem_current_allocated_memory -= size;
00435 
00436   mutex_exit(&mem_hash_mutex);
00437 }
00438 #endif /* UNIV_MEM_DEBUG */
00439 
00440 #if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
00441 /***************************************************************/
00447 UNIV_INTERN
00448 void
00449 mem_heap_validate_or_print(
00450 /*=======================*/
00451   mem_heap_t* heap, 
00452   byte*   /*top __attribute__((unused))*/,
00456   ibool   print,  
00459   ibool*    error,  
00460   ulint*    us_size,
00465   ulint*    ph_size,
00468   ulint*    n_blocks) 
00471 {
00472   mem_block_t*  block;
00473   ulint   total_len = 0;
00474   ulint   block_count = 0;
00475   ulint   phys_len  = 0;
00476 #ifdef UNIV_MEM_DEBUG
00477   ulint   len;
00478   byte*   field;
00479   byte*   user_field;
00480   ulint   check_field;
00481 #endif
00482 
00483   /* Pessimistically, we set the parameters to error values */
00484   if (us_size != NULL) {
00485     *us_size = 0;
00486   }
00487   if (ph_size != NULL) {
00488     *ph_size = 0;
00489   }
00490   if (n_blocks != NULL) {
00491     *n_blocks = 0;
00492   }
00493   *error = TRUE;
00494 
00495   block = heap;
00496 
00497   if (block->magic_n != MEM_BLOCK_MAGIC_N) {
00498     return;
00499   }
00500 
00501   if (print) {
00502     fputs("Memory heap:", stderr);
00503   }
00504 
00505   while (block != NULL) {
00506     phys_len += mem_block_get_len(block);
00507 
00508     if ((block->type == MEM_HEAP_BUFFER)
00509         && (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
00510 
00511       fprintf(stderr,
00512         "InnoDB: Error: mem block %p"
00513         " length %lu > UNIV_PAGE_SIZE\n",
00514         (void*) block,
00515         (ulong) mem_block_get_len(block));
00516       /* error */
00517 
00518       return;
00519     }
00520 
00521 #ifdef UNIV_MEM_DEBUG
00522     /* We can trace the fields of the block only in the debug
00523     version */
00524     if (print) {
00525       fprintf(stderr, " Block %ld:", block_count);
00526     }
00527 
00528     field = (byte*)block + mem_block_get_start(block);
00529 
00530     if (top && (field == top)) {
00531 
00532       goto completed;
00533     }
00534 
00535     while (field < (byte*)block + mem_block_get_free(block)) {
00536 
00537       /* Calculate the pointer to the storage
00538       which was given to the user */
00539 
00540       user_field = field + MEM_FIELD_HEADER_SIZE;
00541 
00542       len = mem_field_header_get_len(user_field);
00543 
00544       if (print) {
00545         ut_print_buf(stderr, user_field, len);
00546         putc('\n', stderr);
00547       }
00548 
00549       total_len += len;
00550       check_field = mem_field_header_get_check(user_field);
00551 
00552       if (check_field
00553           != mem_field_trailer_get_check(user_field)) {
00554         /* error */
00555 
00556         fprintf(stderr,
00557           "InnoDB: Error: block %lx mem"
00558           " field %lx len %lu\n"
00559           "InnoDB: header check field is"
00560           " %lx but trailer %lx\n",
00561           (ulint)block,
00562           (ulint)field, len, check_field,
00563           mem_field_trailer_get_check(
00564             user_field));
00565 
00566         return;
00567       }
00568 
00569       /* Move to next field */
00570       field = field + MEM_SPACE_NEEDED(len);
00571 
00572       if (top && (field == top)) {
00573 
00574         goto completed;
00575       }
00576 
00577     }
00578 
00579     /* At the end check that we have arrived to the first free
00580     position */
00581 
00582     if (field != (byte*)block + mem_block_get_free(block)) {
00583       /* error */
00584 
00585       fprintf(stderr,
00586         "InnoDB: Error: block %lx end of"
00587         " mem fields %lx\n"
00588         "InnoDB: but block free at %lx\n",
00589         (ulint)block, (ulint)field,
00590         (ulint)((byte*)block
00591           + mem_block_get_free(block)));
00592 
00593       return;
00594     }
00595 
00596 #endif
00597 
00598     block = UT_LIST_GET_NEXT(list, block);
00599     block_count++;
00600   }
00601 #ifdef UNIV_MEM_DEBUG
00602 completed:
00603 #endif
00604   if (us_size != NULL) {
00605     *us_size = total_len;
00606   }
00607   if (ph_size != NULL) {
00608     *ph_size = phys_len;
00609   }
00610   if (n_blocks != NULL) {
00611     *n_blocks = block_count;
00612   }
00613   *error = FALSE;
00614 }
00615 
00616 /**************************************************************/
00618 static
00619 void
00620 mem_heap_print(
00621 /*===========*/
00622   mem_heap_t* heap) 
00623 {
00624   ibool error;
00625   ulint us_size;
00626   ulint phys_size;
00627   ulint n_blocks;
00628 
00629   ut_ad(mem_heap_check(heap));
00630 
00631   mem_heap_validate_or_print(heap, NULL, TRUE, &error,
00632            &us_size, &phys_size, &n_blocks);
00633   fprintf(stderr,
00634     "\nheap type: %lu; size: user size %lu;"
00635     " physical size %lu; blocks %lu.\n",
00636     (ulong) heap->type, (ulong) us_size,
00637     (ulong) phys_size, (ulong) n_blocks);
00638   ut_a(!error);
00639 }
00640 
00641 /**************************************************************/
00644 UNIV_INTERN
00645 ibool
00646 mem_heap_validate(
00647 /*==============*/
00648   mem_heap_t* heap) 
00649 {
00650   ibool error;
00651   ulint us_size;
00652   ulint phys_size;
00653   ulint n_blocks;
00654 
00655   ut_ad(mem_heap_check(heap));
00656 
00657   mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
00658            &phys_size, &n_blocks);
00659   if (error) {
00660     mem_heap_print(heap);
00661   }
00662 
00663   ut_a(!error);
00664 
00665   return(TRUE);
00666 }
00667 #endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
00668 
00669 #ifdef UNIV_DEBUG
00670 /**************************************************************/
00673 UNIV_INTERN
00674 ibool
00675 mem_heap_check(
00676 /*===========*/
00677   mem_heap_t* heap) 
00678 {
00679   ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
00680 
00681   return(TRUE);
00682 }
00683 #endif /* UNIV_DEBUG */
00684 
00685 #ifdef UNIV_MEM_DEBUG
00686 /*****************************************************************/
00689 UNIV_INTERN
00690 ibool
00691 mem_all_freed(void)
00692 /*===============*/
00693 {
00694   mem_hash_node_t*  node;
00695   ulint     heap_count  = 0;
00696   ulint     i;
00697 
00698   mem_validate();
00699 
00700   mutex_enter(&mem_hash_mutex);
00701 
00702   for (i = 0; i < MEM_HASH_SIZE; i++) {
00703 
00704     node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
00705     while (node != NULL) {
00706       heap_count++;
00707       node = UT_LIST_GET_NEXT(list, node);
00708     }
00709   }
00710 
00711   mutex_exit(&mem_hash_mutex);
00712 
00713   if (heap_count == 0) {
00714 # ifndef UNIV_HOTBACKUP
00715     ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
00716 # endif /* !UNIV_HOTBACKUP */
00717 
00718     return(TRUE);
00719   } else {
00720     return(FALSE);
00721   }
00722 }
00723 
00724 /*****************************************************************/
00727 UNIV_INTERN
00728 ibool
00729 mem_validate_no_assert(void)
00730 /*========================*/
00731 {
00732   mem_hash_node_t*  node;
00733   ulint     n_heaps     = 0;
00734   ulint     allocated_mem;
00735   ulint     ph_size;
00736   ulint     total_allocated_mem = 0;
00737   ibool     error     = FALSE;
00738   ulint     n_blocks;
00739   ulint     i;
00740 
00741 # ifndef UNIV_HOTBACKUP
00742   mem_pool_validate(mem_comm_pool);
00743 # endif /* !UNIV_HOTBACKUP */
00744 
00745   mutex_enter(&mem_hash_mutex);
00746 
00747   for (i = 0; i < MEM_HASH_SIZE; i++) {
00748 
00749     node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
00750 
00751     while (node != NULL) {
00752       n_heaps++;
00753 
00754       mem_heap_validate_or_print(node->heap, NULL,
00755                FALSE, &error,
00756                &allocated_mem,
00757                &ph_size, &n_blocks);
00758 
00759       if (error) {
00760         fprintf(stderr,
00761           "\nERROR!!!!!!!!!!!!!!!!!!!"
00762           "!!!!!!!!!!!!!!!!!!!!!!!\n\n"
00763           "Inconsistency in memory heap"
00764           " or buffer created\n"
00765           "in %s line %lu.\n",
00766           node->file_name, node->line);
00767 
00768         mutex_exit(&mem_hash_mutex);
00769 
00770         return(TRUE);
00771       }
00772 
00773       total_allocated_mem += allocated_mem;
00774       node = UT_LIST_GET_NEXT(list, node);
00775     }
00776   }
00777 
00778   if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
00779     error = TRUE;
00780   }
00781 
00782   if (mem_total_allocated_memory < mem_current_allocated_memory) {
00783     error = TRUE;
00784   }
00785 
00786   if (mem_max_allocated_memory > mem_total_allocated_memory) {
00787     error = TRUE;
00788   }
00789 
00790   if (mem_n_created_heaps < n_heaps) {
00791     error = TRUE;
00792   }
00793 
00794   mutex_exit(&mem_hash_mutex);
00795 
00796   return(error);
00797 }
00798 
00799 /************************************************************/
00802 UNIV_INTERN
00803 ibool
00804 mem_validate(void)
00805 /*==============*/
00806 {
00807   ut_a(!mem_validate_no_assert());
00808 
00809   return(TRUE);
00810 }
00811 #endif /* UNIV_MEM_DEBUG */
00812 
00813 /************************************************************/
00816 UNIV_INTERN
00817 void
00818 mem_analyze_corruption(
00819 /*===================*/
00820   void* ptr)  
00821 {
00822   byte* p;
00823   ulint i;
00824   ulint dist;
00825 
00826   fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
00827   ut_print_buf(stderr, (byte*)ptr - 250, 500);
00828 
00829   fputs("\nInnoDB: Scanning backward trying to find"
00830         " previous allocated mem blocks\n", stderr);
00831 
00832   p = (byte*)ptr;
00833   dist = 0;
00834 
00835   for (i = 0; i < 10; i++) {
00836     for (;;) {
00837       if (((ulint)p) % 4 == 0) {
00838 
00839         if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
00840           fprintf(stderr,
00841             "Mem block at - %lu,"
00842             " file %s, line %lu\n",
00843             (ulong) dist,
00844             (p + sizeof(ulint)),
00845             (ulong)
00846             (*(ulint*)(p + 8
00847                  + sizeof(ulint))));
00848 
00849           break;
00850         }
00851 
00852         if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
00853           fprintf(stderr,
00854             "Freed mem block at - %lu,"
00855             " file %s, line %lu\n",
00856             (ulong) dist,
00857             (p + sizeof(ulint)),
00858             (ulong)
00859             (*(ulint*)(p + 8
00860                  + sizeof(ulint))));
00861 
00862           break;
00863         }
00864       }
00865 
00866       p--;
00867       dist++;
00868     }
00869 
00870     p--;
00871     dist++;
00872   }
00873 
00874   fprintf(stderr,
00875     "InnoDB: Scanning forward trying to find next"
00876     " allocated mem blocks\n");
00877 
00878   p = (byte*)ptr;
00879   dist = 0;
00880 
00881   for (i = 0; i < 10; i++) {
00882     for (;;) {
00883       if (((ulint)p) % 4 == 0) {
00884 
00885         if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
00886           fprintf(stderr,
00887             "Mem block at + %lu, file %s,"
00888             " line %lu\n",
00889             (ulong) dist,
00890             (p + sizeof(ulint)),
00891             (ulong)
00892             (*(ulint*)(p + 8
00893                  + sizeof(ulint))));
00894 
00895           break;
00896         }
00897 
00898         if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
00899           fprintf(stderr,
00900             "Freed mem block at + %lu,"
00901             " file %s, line %lu\n",
00902             (ulong) dist,
00903             (p + sizeof(ulint)),
00904             (ulong)
00905             (*(ulint*)(p + 8
00906                  + sizeof(ulint))));
00907 
00908           break;
00909         }
00910       }
00911 
00912       p++;
00913       dist++;
00914     }
00915 
00916     p++;
00917     dist++;
00918   }
00919 }
00920 
00921 #ifndef UNIV_HOTBACKUP
00922 /*****************************************************************/
00925 static
00926 void
00927 mem_print_info_low(
00928 /*===============*/
00929   ibool print_all)  
00932 {
00933 #ifdef UNIV_MEM_DEBUG
00934   mem_hash_node_t*  node;
00935   ulint     n_heaps     = 0;
00936   ulint     allocated_mem;
00937   ulint     ph_size;
00938   ulint     total_allocated_mem = 0;
00939   ibool     error;
00940   ulint     n_blocks;
00941 #endif
00942   FILE*     outfile;
00943 
00944   /* outfile = fopen("ibdebug", "a"); */
00945 
00946   outfile = stdout;
00947 
00948   fprintf(outfile, "\n");
00949   fprintf(outfile,
00950     "________________________________________________________\n");
00951   fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
00952 
00953 #ifndef UNIV_MEM_DEBUG
00954 
00955   UT_NOT_USED(print_all);
00956 
00957   mem_pool_print_info(outfile, mem_comm_pool);
00958 
00959   fprintf(outfile,
00960     "Sorry, non-debug version cannot give more memory info\n");
00961 
00962   /* fclose(outfile); */
00963 
00964   return;
00965 #else
00966   mutex_enter(&mem_hash_mutex);
00967 
00968   fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
00969 
00970   if (!print_all) {
00971     fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
00972   }
00973 
00974   node = UT_LIST_GET_FIRST(mem_all_list_base);
00975 
00976   while (node != NULL) {
00977     n_heaps++;
00978 
00979     if (!print_all && node->nth_heap < mem_last_print_info) {
00980 
00981       goto next_heap;
00982     }
00983 
00984     mem_heap_validate_or_print(node->heap, NULL,
00985              FALSE, &error, &allocated_mem,
00986              &ph_size, &n_blocks);
00987     total_allocated_mem += allocated_mem;
00988 
00989     fprintf(outfile,
00990       "%lu: file %s line %lu of size %lu phys.size %lu"
00991       " with %lu blocks, type %lu\n",
00992       node->nth_heap, node->file_name, node->line,
00993       allocated_mem, ph_size, n_blocks,
00994       (node->heap)->type);
00995 next_heap:
00996     node = UT_LIST_GET_NEXT(all_list, node);
00997   }
00998 
00999   fprintf(outfile, "\n");
01000 
01001   fprintf(outfile, "Current allocated memory              : %lu\n",
01002     mem_current_allocated_memory);
01003   fprintf(outfile, "Current allocated heaps and buffers   : %lu\n",
01004     n_heaps);
01005   fprintf(outfile, "Cumulative allocated memory           : %lu\n",
01006     mem_total_allocated_memory);
01007   fprintf(outfile, "Maximum allocated memory              : %lu\n",
01008     mem_max_allocated_memory);
01009   fprintf(outfile, "Cumulative created heaps and buffers  : %lu\n",
01010     mem_n_created_heaps);
01011   fprintf(outfile, "Cumulative number of allocations      : %lu\n",
01012     mem_n_allocations);
01013 
01014   mem_last_print_info = mem_n_created_heaps;
01015 
01016   mutex_exit(&mem_hash_mutex);
01017 
01018   mem_pool_print_info(outfile, mem_comm_pool);
01019 
01020   /*  mem_validate(); */
01021 
01022   /*  fclose(outfile); */
01023 #endif
01024 }
01025 
01026 /*****************************************************************/
01029 UNIV_INTERN
01030 void
01031 mem_print_info(void)
01032 /*================*/
01033 {
01034   mem_print_info_low(TRUE);
01035 }
01036 
01037 /*****************************************************************/
01040 UNIV_INTERN
01041 void
01042 mem_print_new_info(void)
01043 /*====================*/
01044 {
01045   mem_print_info_low(FALSE);
01046 }
01047 #endif /* !UNIV_HOTBACKUP */