Drizzled Public API Documentation

mem0mem.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 /********************************************************************/
00026 #include "mem0mem.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "mem0mem.ic"
00030 #endif
00031 
00032 #include "buf0buf.h"
00033 #include "srv0srv.h"
00034 #include "mem0dbg.cc"
00035 #include <stdarg.h>
00036 
00037 /*
00038       THE MEMORY MANAGEMENT
00039       =====================
00040 
00041 The basic element of the memory management is called a memory
00042 heap. A memory heap is conceptually a
00043 stack from which memory can be allocated. The stack may grow infinitely.
00044 The top element of the stack may be freed, or
00045 the whole stack can be freed at one time. The advantage of the
00046 memory heap concept is that we can avoid using the malloc and free
00047 functions of C which are quite expensive, for example, on the Solaris + GCC
00048 system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
00049 on Win NT + 100MHz Pentium, 2.5 microseconds.
00050 When we use a memory heap,
00051 we can allocate larger blocks of memory at a time and thus
00052 reduce overhead. Slightly more efficient the method is when we
00053 allocate the memory from the index page buffer pool, as we can
00054 claim a new page fast. This is called buffer allocation.
00055 When we allocate the memory from the dynamic memory of the
00056 C environment, that is called dynamic allocation.
00057 
00058 The default way of operation of the memory heap is the following.
00059 First, when the heap is created, an initial block of memory is
00060 allocated. In dynamic allocation this may be about 50 bytes.
00061 If more space is needed, additional blocks are allocated
00062 and they are put into a linked list.
00063 After the initial block, each allocated block is twice the size of the
00064 previous, until a threshold is attained, after which the sizes
00065 of the blocks stay the same. An exception is, of course, the case
00066 where the caller requests a memory buffer whose size is
00067 bigger than the threshold. In that case a block big enough must
00068 be allocated.
00069 
00070 The heap is physically arranged so that if the current block
00071 becomes full, a new block is allocated and always inserted in the
00072 chain of blocks as the last block.
00073 
00074 In the debug version of the memory management, all the allocated
00075 heaps are kept in a list (which is implemented as a hash table).
00076 Thus we can notice if the caller tries to free an already freed
00077 heap. In addition, each buffer given to the caller contains
00078 start field at the start and a trailer field at the end of the buffer.
00079 
00080 The start field has the following content:
00081 A. sizeof(ulint) bytes of field length (in the standard byte order)
00082 B. sizeof(ulint) bytes of check field (a random number)
00083 
00084 The trailer field contains:
00085 A. sizeof(ulint) bytes of check field (the same random number as at the start)
00086 
00087 Thus we can notice if something has been copied over the
00088 borders of the buffer, which is illegal.
00089 The memory in the buffers is initialized to a random byte sequence.
00090 After freeing, all the blocks in the heap are set to random bytes
00091 to help us discover errors which result from the use of
00092 buffers in an already freed heap. */
00093 
00094 #ifdef MEM_PERIODIC_CHECK
00095 
00096 ibool         mem_block_list_inited;
00097 /* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
00098 UT_LIST_BASE_NODE_T(mem_block_t)  mem_block_list;
00099 
00100 #endif
00101 
00102 /**********************************************************************/
00105 UNIV_INTERN
00106 char*
00107 mem_heap_strdup(
00108 /*============*/
00109   mem_heap_t* heap, 
00110   const char* str)  
00111 {
00112   return(static_cast<char *>(mem_heap_dup(heap, str, strlen(str) + 1)));
00113 }
00114 
00115 /**********************************************************************/
00118 UNIV_INTERN
00119 void*
00120 mem_heap_dup(
00121 /*=========*/
00122   mem_heap_t* heap, 
00123   const void* data, 
00124   ulint   len)  
00125 {
00126   return(memcpy(mem_heap_alloc(heap, len), data, len));
00127 }
00128 
00129 /**********************************************************************/
00132 UNIV_INTERN
00133 char*
00134 mem_heap_strcat(
00135 /*============*/
00136   mem_heap_t* heap, 
00137   const char* s1, 
00138   const char* s2) 
00139 {
00140   char* s;
00141   ulint s1_len = strlen(s1);
00142   ulint s2_len = strlen(s2);
00143 
00144   s = static_cast<char *>(mem_heap_alloc(heap, s1_len + s2_len + 1));
00145 
00146   memcpy(s, s1, s1_len);
00147   memcpy(s + s1_len, s2, s2_len);
00148 
00149   s[s1_len + s2_len] = '\0';
00150 
00151   return(s);
00152 }
00153 
00154 
00155 /****************************************************************/
00158 static
00159 ulint
00160 mem_heap_printf_low(
00161 /*================*/
00162   char*   buf,  
00164   const char* format, 
00165   va_list   ap) 
00166 {
00167   ulint     len = 0;
00168 
00169   while (*format) {
00170 
00171     /* Does this format specifier have the 'l' length modifier. */
00172     ibool is_long = FALSE;
00173 
00174     /* Length of one parameter. */
00175     size_t  plen;
00176 
00177     if (*format++ != '%') {
00178       /* Non-format character. */
00179 
00180       len++;
00181 
00182       if (buf) {
00183         *buf++ = *(format - 1);
00184       }
00185 
00186       continue;
00187     }
00188 
00189     if (*format == 'l') {
00190       is_long = TRUE;
00191       format++;
00192     }
00193 
00194     switch (*format++) {
00195     case 's':
00196       /* string */
00197       {
00198         char* s = va_arg(ap, char*);
00199 
00200         /* "%ls" is a non-sensical format specifier. */
00201         ut_a(!is_long);
00202 
00203         plen = strlen(s);
00204         len += plen;
00205 
00206         if (buf) {
00207           memcpy(buf, s, plen);
00208           buf += plen;
00209         }
00210       }
00211 
00212       break;
00213 
00214     case 'u':
00215       /* unsigned int */
00216       {
00217         char    tmp[32];
00218         unsigned long val;
00219 
00220         /* We only support 'long' values for now. */
00221         ut_a(is_long);
00222 
00223         val = va_arg(ap, unsigned long);
00224 
00225         plen = sprintf(tmp, "%lu", val);
00226         len += plen;
00227 
00228         if (buf) {
00229           memcpy(buf, tmp, plen);
00230           buf += plen;
00231         }
00232       }
00233 
00234       break;
00235 
00236     case '%':
00237 
00238       /* "%l%" is a non-sensical format specifier. */
00239       ut_a(!is_long);
00240 
00241       len++;
00242 
00243       if (buf) {
00244         *buf++ = '%';
00245       }
00246 
00247       break;
00248 
00249     default:
00250       ut_error;
00251     }
00252   }
00253 
00254   /* For the NUL character. */
00255   len++;
00256 
00257   if (buf) {
00258     *buf = '\0';
00259   }
00260 
00261   return(len);
00262 }
00263 
00264 /****************************************************************/
00270 UNIV_INTERN
00271 char*
00272 mem_heap_printf(
00273 /*============*/
00274   mem_heap_t* heap, 
00275   const char* format, 
00276   ...)
00277 {
00278   va_list   ap;
00279   char*   str;
00280   ulint     len;
00281 
00282   /* Calculate length of string */
00283   len = 0;
00284   va_start(ap, format);
00285   len = mem_heap_printf_low(NULL, format, ap);
00286   va_end(ap);
00287 
00288   /* Now create it for real. */
00289   str = static_cast<char *>(mem_heap_alloc(heap, len));
00290   va_start(ap, format);
00291   mem_heap_printf_low(str, format, ap);
00292   va_end(ap);
00293 
00294   return(str);
00295 }
00296 
00297 /***************************************************************/
00301 UNIV_INTERN
00302 mem_block_t*
00303 mem_heap_create_block(
00304 /*==================*/
00305   mem_heap_t* heap, 
00307   ulint   n,  
00308   ulint   type, 
00310   const char* file_name,
00311   ulint   line) 
00312 {
00313 #ifndef UNIV_HOTBACKUP
00314   buf_block_t*  buf_block = NULL;
00315 #endif /* !UNIV_HOTBACKUP */
00316   mem_block_t*  block;
00317   ulint   len;
00318 
00319   ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
00320         || (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
00321 
00322   if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
00323     mem_analyze_corruption(heap);
00324   }
00325 
00326   /* In dynamic allocation, calculate the size: block header + data. */
00327   len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
00328 
00329 #ifndef UNIV_HOTBACKUP
00330   if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
00331 
00332     ut_ad(type == MEM_HEAP_DYNAMIC || n <= MEM_MAX_ALLOC_IN_BUF);
00333 
00334     block = static_cast<mem_block_info_t *>(mem_area_alloc(&len, mem_comm_pool));
00335   } else {
00336     len = UNIV_PAGE_SIZE;
00337 
00338     if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
00339       /* We cannot allocate the block from the
00340       buffer pool, but must get the free block from
00341       the heap header free block field */
00342 
00343       buf_block = static_cast<buf_block_t *>(heap->free_block);
00344       heap->free_block = NULL;
00345 
00346       if (UNIV_UNLIKELY(!buf_block)) {
00347 
00348         return(NULL);
00349       }
00350     } else {
00351       buf_block = buf_block_alloc(NULL, 0);
00352     }
00353 
00354     block = (mem_block_t*) buf_block->frame;
00355   }
00356 
00357   ut_ad(block);
00358   block->buf_block = buf_block;
00359   block->free_block = NULL;
00360 #else /* !UNIV_HOTBACKUP */
00361   len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
00362   block = ut_malloc(len);
00363   ut_ad(block);
00364 #endif /* !UNIV_HOTBACKUP */
00365 
00366   block->magic_n = MEM_BLOCK_MAGIC_N;
00367   ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
00368   block->line = line;
00369 
00370 #ifdef MEM_PERIODIC_CHECK
00371   mutex_enter(&(mem_comm_pool->mutex));
00372 
00373   if (!mem_block_list_inited) {
00374     mem_block_list_inited = TRUE;
00375     UT_LIST_INIT(mem_block_list);
00376   }
00377 
00378   UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
00379 
00380   mutex_exit(&(mem_comm_pool->mutex));
00381 #endif
00382   mem_block_set_len(block, len);
00383   mem_block_set_type(block, type);
00384   mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
00385   mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
00386 
00387   if (UNIV_UNLIKELY(heap == NULL)) {
00388     /* This is the first block of the heap. The field
00389     total_size should be initialized here */
00390     block->total_size = len;
00391   } else {
00392     /* Not the first allocation for the heap. This block's
00393     total_length field should be set to undefined. */
00394     ut_d(block->total_size = ULINT_UNDEFINED);
00395     UNIV_MEM_INVALID(&block->total_size,
00396          sizeof block->total_size);
00397 
00398     heap->total_size += len;
00399   }
00400 
00401   ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
00402 
00403   return(block);
00404 }
00405 
00406 /***************************************************************/
00410 UNIV_INTERN
00411 mem_block_t*
00412 mem_heap_add_block(
00413 /*===============*/
00414   mem_heap_t* heap, 
00415   ulint   n)  
00416 {
00417   mem_block_t*  block;
00418   mem_block_t*  new_block;
00419   ulint   new_size;
00420 
00421   ut_ad(mem_heap_check(heap));
00422 
00423   block = UT_LIST_GET_LAST(heap->base);
00424 
00425   /* We have to allocate a new block. The size is always at least
00426   doubled until the standard size is reached. After that the size
00427   stays the same, except in cases where the caller needs more space. */
00428 
00429   new_size = 2 * mem_block_get_len(block);
00430 
00431   if (heap->type != MEM_HEAP_DYNAMIC) {
00432     /* From the buffer pool we allocate buffer frames */
00433     ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
00434 
00435     if (new_size > MEM_MAX_ALLOC_IN_BUF) {
00436       new_size = MEM_MAX_ALLOC_IN_BUF;
00437     }
00438   } else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
00439 
00440     new_size = MEM_BLOCK_STANDARD_SIZE;
00441   }
00442 
00443   if (new_size < n) {
00444     new_size = n;
00445   }
00446 
00447   new_block = mem_heap_create_block(heap, new_size, heap->type,
00448             heap->file_name, heap->line);
00449   if (new_block == NULL) {
00450 
00451     return(NULL);
00452   }
00453 
00454   /* Add the new block as the last block */
00455 
00456   UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
00457 
00458   return(new_block);
00459 }
00460 
00461 /******************************************************************/
00463 UNIV_INTERN
00464 void
00465 mem_heap_block_free(
00466 /*================*/
00467   mem_heap_t* heap, 
00468   mem_block_t*  block)  
00469 {
00470   ulint   type;
00471   ulint   len;
00472 #ifndef UNIV_HOTBACKUP
00473   buf_block_t*  buf_block = static_cast<buf_block_t *>(block->buf_block);
00474 #endif /* !UNIV_HOTBACKUP */
00475 
00476   if (block->magic_n != MEM_BLOCK_MAGIC_N) {
00477     mem_analyze_corruption(block);
00478   }
00479 
00480   UT_LIST_REMOVE(list, heap->base, block);
00481 
00482 #ifdef MEM_PERIODIC_CHECK
00483   mutex_enter(&(mem_comm_pool->mutex));
00484 
00485   UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
00486 
00487   mutex_exit(&(mem_comm_pool->mutex));
00488 #endif
00489 
00490   ut_ad(heap->total_size >= block->len);
00491   heap->total_size -= block->len;
00492 
00493   type = heap->type;
00494   len = block->len;
00495   block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
00496 
00497 #ifndef UNIV_HOTBACKUP
00498 #ifdef UNIV_MEM_DEBUG
00499   /* In the debug version we set the memory to a random combination
00500   of hex 0xDE and 0xAD. */
00501 
00502   mem_erase_buf((byte*)block, len);
00503 #else /* UNIV_MEM_DEBUG */
00504   UNIV_MEM_ASSERT_AND_FREE(block, len);
00505 #endif /* UNIV_MEM_DEBUG */
00506 
00507   if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
00508 
00509     ut_ad(!buf_block);
00510     mem_area_free(block, mem_comm_pool);
00511   } else {
00512     ut_ad(type & MEM_HEAP_BUFFER);
00513 
00514     buf_block_free(buf_block);
00515   }
00516 #else /* !UNIV_HOTBACKUP */
00517 #ifdef UNIV_MEM_DEBUG
00518   /* In the debug version we set the memory to a random
00519   combination of hex 0xDE and 0xAD. */
00520 
00521   mem_erase_buf((byte*)block, len);
00522 #else /* UNIV_MEM_DEBUG */
00523   UNIV_MEM_ASSERT_AND_FREE(block, len);
00524 #endif /* UNIV_MEM_DEBUG */
00525   ut_free(block);
00526 #endif /* !UNIV_HOTBACKUP */
00527 }
00528 
00529 #ifndef UNIV_HOTBACKUP
00530 /******************************************************************/
00532 UNIV_INTERN
00533 void
00534 mem_heap_free_block_free(
00535 /*=====================*/
00536   mem_heap_t* heap) 
00537 {
00538   if (UNIV_LIKELY_NULL(heap->free_block)) {
00539 
00540     buf_block_free(static_cast<buf_block_t *>(heap->free_block));
00541 
00542     heap->free_block = NULL;
00543   }
00544 }
00545 #endif /* !UNIV_HOTBACKUP */
00546 
00547 #ifdef MEM_PERIODIC_CHECK
00548 /******************************************************************/
00551 UNIV_INTERN
00552 void
00553 mem_validate_all_blocks(void)
00554 /*=========================*/
00555 {
00556   mem_block_t*  block;
00557 
00558   mutex_enter(&(mem_comm_pool->mutex));
00559 
00560   block = UT_LIST_GET_FIRST(mem_block_list);
00561 
00562   while (block) {
00563     if (block->magic_n != MEM_BLOCK_MAGIC_N) {
00564       mem_analyze_corruption(block);
00565     }
00566 
00567     block = UT_LIST_GET_NEXT(mem_block_list, block);
00568   }
00569 
00570   mutex_exit(&(mem_comm_pool->mutex));
00571 }
00572 #endif