Drizzled Public API Documentation

ut0mem.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2009, 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 "ut0mem.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "ut0mem.ic"
00030 #endif
00031 
00032 #ifndef UNIV_HOTBACKUP
00033 # include "os0thread.h"
00034 # include "srv0srv.h"
00035 
00036 #include <stdlib.h>
00037 #include <errno.h>
00038 
00040 typedef struct ut_mem_block_struct ut_mem_block_t;
00041 
00045 UNIV_INTERN ulint   ut_total_allocated_memory = 0;
00046 
00048 UNIV_INTERN os_fast_mutex_t ut_list_mutex;
00049 
00051 struct ut_mem_block_struct{
00052   UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
00054   ulint size; 
00055   ulint magic_n;
00056 };
00057 
00060 #define UT_MEM_MAGIC_N  1601650166
00061 
00064 static UT_LIST_BASE_NODE_T(ut_mem_block_t)   ut_mem_block_list;
00065 
00067 static ibool  ut_mem_block_list_inited = FALSE;
00068 
00071 static ulint* ut_mem_null_ptr = NULL;
00072 
00073 /**********************************************************************/
00075 UNIV_INTERN
00076 void
00077 ut_mem_init(void)
00078 /*=============*/
00079 {
00080   ut_a(!ut_mem_block_list_inited);
00081   os_fast_mutex_init(&ut_list_mutex);
00082   UT_LIST_INIT(ut_mem_block_list);
00083   ut_mem_block_list_inited = TRUE;
00084 }
00085 #endif /* !UNIV_HOTBACKUP */
00086 
00087 /**********************************************************************/
00091 UNIV_INTERN
00092 void*
00093 ut_malloc_low(
00094 /*==========*/
00095   ulint n,    
00096   ibool set_to_zero,  
00099   ibool assert_on_error)
00101 {
00102 #ifndef UNIV_HOTBACKUP
00103   ulint retry_count;
00104   void* ret;
00105 
00106   if (UNIV_LIKELY(srv_use_sys_malloc)) {
00107     ret = malloc(n);
00108     ut_a(ret || !assert_on_error);
00109 
00110 #ifdef UNIV_SET_MEM_TO_ZERO
00111     if (set_to_zero) {
00112       memset(ret, '\0', n);
00113       UNIV_MEM_ALLOC(ret, n);
00114     }
00115 #endif
00116     return(ret);
00117   }
00118 
00119   ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
00120   ut_a(ut_mem_block_list_inited);
00121 
00122   retry_count = 0;
00123 retry:
00124   os_fast_mutex_lock(&ut_list_mutex);
00125 
00126   ret = malloc(n + sizeof(ut_mem_block_t));
00127 
00128   if (ret == NULL && retry_count < 60) {
00129     if (retry_count == 0) {
00130       ut_print_timestamp(stderr);
00131 
00132       fprintf(stderr,
00133         "  InnoDB: Error: cannot allocate"
00134         " %lu bytes of\n"
00135         "InnoDB: memory with malloc!"
00136         " Total allocated memory\n"
00137         "InnoDB: by InnoDB %lu bytes."
00138         " Operating system errno: %lu\n"
00139         "InnoDB: Check if you should"
00140         " increase the swap file or\n"
00141         "InnoDB: ulimits of your operating system.\n"
00142         "InnoDB: On FreeBSD check you"
00143         " have compiled the OS with\n"
00144         "InnoDB: a big enough maximum process size.\n"
00145         "InnoDB: Note that in most 32-bit"
00146         " computers the process\n"
00147         "InnoDB: memory space is limited"
00148         " to 2 GB or 4 GB.\n"
00149         "InnoDB: We keep retrying"
00150         " the allocation for 60 seconds...\n",
00151         (ulong) n, (ulong) ut_total_allocated_memory,
00152 #ifdef __WIN__
00153         (ulong) GetLastError()
00154 #else
00155         (ulong) errno
00156 #endif
00157         );
00158     }
00159 
00160     os_fast_mutex_unlock(&ut_list_mutex);
00161 
00162     /* Sleep for a second and retry the allocation; maybe this is
00163     just a temporary shortage of memory */
00164 
00165     os_thread_sleep(1000000);
00166 
00167     retry_count++;
00168 
00169     goto retry;
00170   }
00171 
00172   if (ret == NULL) {
00173     /* Flush stderr to make more probable that the error
00174     message gets in the error file before we generate a seg
00175     fault */
00176 
00177     fflush(stderr);
00178 
00179     os_fast_mutex_unlock(&ut_list_mutex);
00180 
00181     /* Make an intentional seg fault so that we get a stack
00182     trace */
00183     if (assert_on_error) {
00184       ut_print_timestamp(stderr);
00185 
00186       fprintf(stderr,
00187         "  InnoDB: We now intentionally"
00188         " generate a seg fault so that\n"
00189         "InnoDB: on Linux we get a stack trace.\n");
00190 
00191       if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
00192     } else {
00193       return(NULL);
00194     }
00195   }
00196 
00197   if (set_to_zero) {
00198 #ifdef UNIV_SET_MEM_TO_ZERO
00199     memset(ret, '\0', n + sizeof(ut_mem_block_t));
00200 #endif
00201   }
00202 
00203   UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
00204 
00205   ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
00206   ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
00207 
00208   ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
00209 
00210   UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
00211         ((ut_mem_block_t*)ret));
00212   os_fast_mutex_unlock(&ut_list_mutex);
00213 
00214   return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
00215 #else /* !UNIV_HOTBACKUP */
00216   void* ret = malloc(n);
00217   ut_a(ret || !assert_on_error);
00218 
00219 # ifdef UNIV_SET_MEM_TO_ZERO
00220   if (set_to_zero) {
00221     memset(ret, '\0', n);
00222   }
00223 # endif
00224   return(ret);
00225 #endif /* !UNIV_HOTBACKUP */
00226 }
00227 
00228 /**********************************************************************/
00232 extern "C"
00233 UNIV_INTERN
00234 void*
00235 ut_malloc(
00236 /*======*/
00237   ulint n)  
00238 {
00239 #ifndef UNIV_HOTBACKUP
00240   return(ut_malloc_low(n, TRUE, TRUE));
00241 #else /* !UNIV_HOTBACKUP */
00242   return(malloc(n));
00243 #endif /* !UNIV_HOTBACKUP */
00244 }
00245 
00246 #ifndef UNIV_HOTBACKUP
00247 /**********************************************************************/
00252 UNIV_INTERN
00253 ibool
00254 ut_test_malloc(
00255 /*===========*/
00256   ulint n)  
00257 {
00258   void* ret;
00259 
00260   ret = malloc(n);
00261 
00262   if (ret == NULL) {
00263     ut_print_timestamp(stderr);
00264     fprintf(stderr,
00265       "  InnoDB: Error: cannot allocate"
00266       " %lu bytes of memory for\n"
00267       "InnoDB: a BLOB with malloc! Total allocated memory\n"
00268       "InnoDB: by InnoDB %lu bytes."
00269       " Operating system errno: %d\n"
00270       "InnoDB: Check if you should increase"
00271       " the swap file or\n"
00272       "InnoDB: ulimits of your operating system.\n"
00273       "InnoDB: On FreeBSD check you have"
00274       " compiled the OS with\n"
00275       "InnoDB: a big enough maximum process size.\n",
00276       (ulong) n,
00277       (ulong) ut_total_allocated_memory,
00278       (int) errno);
00279     return(FALSE);
00280   }
00281 
00282   free(ret);
00283 
00284   return(TRUE);
00285 }
00286 #endif /* !UNIV_HOTBACKUP */
00287 
00288 /**********************************************************************/
00291 extern "C"
00292 UNIV_INTERN
00293 void
00294 ut_free(
00295 /*====*/
00296   void* ptr)  
00297 {
00298 #ifndef UNIV_HOTBACKUP
00299   ut_mem_block_t* block;
00300 
00301   if (ptr == NULL) {
00302     return;
00303   } else if (UNIV_LIKELY(srv_use_sys_malloc)) {
00304     free(ptr);
00305     return;
00306   }
00307 
00308   block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
00309 
00310   os_fast_mutex_lock(&ut_list_mutex);
00311 
00312   ut_a(block->magic_n == UT_MEM_MAGIC_N);
00313   ut_a(ut_total_allocated_memory >= block->size);
00314 
00315   ut_total_allocated_memory -= block->size;
00316 
00317   UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
00318   free(block);
00319 
00320   os_fast_mutex_unlock(&ut_list_mutex);
00321 #else /* !UNIV_HOTBACKUP */
00322   free(ptr);
00323 #endif /* !UNIV_HOTBACKUP */
00324 }
00325 
00326 #ifndef UNIV_HOTBACKUP
00327 /**********************************************************************/
00352 extern "C"
00353 UNIV_INTERN
00354 void*
00355 ut_realloc(
00356 /*=======*/
00357   void* ptr,  
00358   ulint size) 
00359 {
00360   ut_mem_block_t* block;
00361   ulint   old_size;
00362   ulint   min_size;
00363   void*   new_ptr;
00364 
00365   if (UNIV_LIKELY(srv_use_sys_malloc)) {
00366     return(realloc(ptr, size));
00367   }
00368 
00369   if (ptr == NULL) {
00370 
00371     return(ut_malloc(size));
00372   }
00373 
00374   if (size == 0) {
00375     ut_free(ptr);
00376 
00377     return(NULL);
00378   }
00379 
00380   block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
00381 
00382   ut_a(block->magic_n == UT_MEM_MAGIC_N);
00383 
00384   old_size = block->size - sizeof(ut_mem_block_t);
00385 
00386   if (size < old_size) {
00387     min_size = size;
00388   } else {
00389     min_size = old_size;
00390   }
00391 
00392   new_ptr = ut_malloc(size);
00393 
00394   if (new_ptr == NULL) {
00395 
00396     return(NULL);
00397   }
00398 
00399   /* Copy the old data from ptr */
00400   ut_memcpy(new_ptr, ptr, min_size);
00401 
00402   ut_free(ptr);
00403 
00404   return(new_ptr);
00405 }
00406 
00407 /**********************************************************************/
00409 UNIV_INTERN
00410 void
00411 ut_free_all_mem(void)
00412 /*=================*/
00413 {
00414   ut_mem_block_t* block;
00415 
00416   ut_a(ut_mem_block_list_inited);
00417   ut_mem_block_list_inited = FALSE;
00418   os_fast_mutex_free(&ut_list_mutex);
00419 
00420   while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
00421 
00422     ut_a(block->magic_n == UT_MEM_MAGIC_N);
00423     ut_a(ut_total_allocated_memory >= block->size);
00424 
00425     ut_total_allocated_memory -= block->size;
00426 
00427     UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
00428     free(block);
00429   }
00430 
00431   if (ut_total_allocated_memory != 0) {
00432     fprintf(stderr,
00433       "InnoDB: Warning: after shutdown"
00434       " total allocated memory is %lu\n",
00435       (ulong) ut_total_allocated_memory);
00436   }
00437 
00438   ut_mem_block_list_inited = FALSE;
00439 }
00440 #endif /* !UNIV_HOTBACKUP */
00441 
00442 /**********************************************************************/
00447 UNIV_INTERN
00448 ulint
00449 ut_strlcpy(
00450 /*=======*/
00451   char*   dst,  
00452   const char* src,  
00453   ulint   size) 
00454 {
00455   ulint src_size = strlen(src);
00456 
00457   if (size != 0) {
00458     ulint n = ut_min(src_size, size - 1);
00459 
00460     memcpy(dst, src, n);
00461     dst[n] = '\0';
00462   }
00463 
00464   return(src_size);
00465 }
00466 
00467 /**********************************************************************/
00471 UNIV_INTERN
00472 ulint
00473 ut_strlcpy_rev(
00474 /*===========*/
00475   char*   dst,  
00476   const char* src,  
00477   ulint   size) 
00478 {
00479   ulint src_size = strlen(src);
00480 
00481   if (size != 0) {
00482     ulint n = ut_min(src_size, size - 1);
00483 
00484     memcpy(dst, src + src_size - n, n + 1);
00485   }
00486 
00487   return(src_size);
00488 }
00489 
00490 /**********************************************************************/
00495 UNIV_INTERN
00496 char*
00497 ut_strcpyq(
00498 /*=======*/
00499   char*   dest, 
00500   char    q,  
00501   const char* src)  
00502 {
00503   while (*src) {
00504     if ((*dest++ = *src++) == q) {
00505       *dest++ = q;
00506     }
00507   }
00508 
00509   return(dest);
00510 }
00511 
00512 /**********************************************************************/
00517 UNIV_INTERN
00518 char*
00519 ut_memcpyq(
00520 /*=======*/
00521   char*   dest, 
00522   char    q,  
00523   const char* src,  
00524   ulint   len)  
00525 {
00526   const char* srcend = src + len;
00527 
00528   while (src < srcend) {
00529     if ((*dest++ = *src++) == q) {
00530       *dest++ = q;
00531     }
00532   }
00533 
00534   return(dest);
00535 }
00536 
00537 #ifndef UNIV_HOTBACKUP
00538 /**********************************************************************/
00542 UNIV_INTERN
00543 ulint
00544 ut_strcount(
00545 /*========*/
00546   const char* s1, 
00547   const char* s2) 
00548 {
00549   ulint count = 0;
00550   ulint len = strlen(s2);
00551 
00552   if (len == 0) {
00553 
00554     return(0);
00555   }
00556 
00557   for (;;) {
00558     s1 = strstr(s1, s2);
00559 
00560     if (!s1) {
00561 
00562       break;
00563     }
00564 
00565     count++;
00566     s1 += len;
00567   }
00568 
00569   return(count);
00570 }
00571 
00572 /**********************************************************************/
00576 UNIV_INTERN
00577 char*
00578 ut_strreplace(
00579 /*==========*/
00580   const char* str,  
00581   const char* s1, 
00582   const char* s2) 
00583 {
00584   char*   new_str;
00585   char*   ptr;
00586   const char* str_end;
00587   ulint   str_len = strlen(str);
00588   ulint   s1_len = strlen(s1);
00589   ulint   s2_len = strlen(s2);
00590   ulint   count = 0;
00591   int   len_delta = (int)s2_len - (int)s1_len;
00592 
00593   str_end = str + str_len;
00594 
00595   if (len_delta <= 0) {
00596     len_delta = 0;
00597   } else {
00598     count = ut_strcount(str, s1);
00599   }
00600 
00601   new_str = static_cast<char *>(mem_alloc(str_len + count * len_delta + 1));
00602   ptr = new_str;
00603 
00604   while (str) {
00605     const char* next = strstr(str, s1);
00606 
00607     if (!next) {
00608       next = str_end;
00609     }
00610 
00611     memcpy(ptr, str, next - str);
00612     ptr += next - str;
00613 
00614     if (next == str_end) {
00615 
00616       break;
00617     }
00618 
00619     memcpy(ptr, s2, s2_len);
00620     ptr += s2_len;
00621 
00622     str = next + s1_len;
00623   }
00624 
00625   *ptr = '\0';
00626 
00627   return(new_str);
00628 }
00629 
00630 #ifdef UNIV_COMPILE_TEST_FUNCS
00631 
00632 void
00633 test_ut_str_sql_format()
00634 {
00635   char  buf[128];
00636   ulint ret;
00637 
00638 #define CALL_AND_TEST(str, str_len, buf, buf_size, ret_expected, buf_expected)\
00639   do {\
00640     ibool ok = TRUE;\
00641     memset(buf, 'x', 10);\
00642     buf[10] = '\0';\
00643     fprintf(stderr, "TESTING \"%s\", %lu, %lu\n",\
00644       str, (ulint) str_len, (ulint) buf_size);\
00645     ret = ut_str_sql_format(str, str_len, buf, buf_size);\
00646     if (ret != ret_expected) {\
00647       fprintf(stderr, "expected ret %lu, got %lu\n",\
00648         (ulint) ret_expected, ret);\
00649       ok = FALSE;\
00650     }\
00651     if (strcmp((char*) buf, buf_expected) != 0) {\
00652       fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
00653         buf_expected, buf);\
00654       ok = FALSE;\
00655     }\
00656     if (ok) {\
00657       fprintf(stderr, "OK: %lu, \"%s\"\n\n",\
00658         (ulint) ret, buf);\
00659     } else {\
00660       return;\
00661     }\
00662   } while (0)
00663 
00664   CALL_AND_TEST("abcd", 4, buf, 0, 0, "xxxxxxxxxx");
00665 
00666   CALL_AND_TEST("abcd", 4, buf, 1, 1, "");
00667 
00668   CALL_AND_TEST("abcd", 4, buf, 2, 1, "");
00669 
00670   CALL_AND_TEST("abcd", 0, buf, 3, 3, "''");
00671   CALL_AND_TEST("abcd", 1, buf, 3, 1, "");
00672   CALL_AND_TEST("abcd", 2, buf, 3, 1, "");
00673   CALL_AND_TEST("abcd", 3, buf, 3, 1, "");
00674   CALL_AND_TEST("abcd", 4, buf, 3, 1, "");
00675 
00676   CALL_AND_TEST("abcd", 0, buf, 4, 3, "''");
00677   CALL_AND_TEST("abcd", 1, buf, 4, 4, "'a'");
00678   CALL_AND_TEST("abcd", 2, buf, 4, 4, "'a'");
00679   CALL_AND_TEST("abcd", 3, buf, 4, 4, "'a'");
00680   CALL_AND_TEST("abcd", 4, buf, 4, 4, "'a'");
00681   CALL_AND_TEST("abcde", 5, buf, 4, 4, "'a'");
00682   CALL_AND_TEST("'", 1, buf, 4, 3, "''");
00683   CALL_AND_TEST("''", 2, buf, 4, 3, "''");
00684   CALL_AND_TEST("a'", 2, buf, 4, 4, "'a'");
00685   CALL_AND_TEST("'a", 2, buf, 4, 3, "''");
00686   CALL_AND_TEST("ab", 2, buf, 4, 4, "'a'");
00687 
00688   CALL_AND_TEST("abcdef", 0, buf, 5, 3, "''");
00689   CALL_AND_TEST("abcdef", 1, buf, 5, 4, "'a'");
00690   CALL_AND_TEST("abcdef", 2, buf, 5, 5, "'ab'");
00691   CALL_AND_TEST("abcdef", 3, buf, 5, 5, "'ab'");
00692   CALL_AND_TEST("abcdef", 4, buf, 5, 5, "'ab'");
00693   CALL_AND_TEST("abcdef", 5, buf, 5, 5, "'ab'");
00694   CALL_AND_TEST("abcdef", 6, buf, 5, 5, "'ab'");
00695   CALL_AND_TEST("'", 1, buf, 5, 5, "''''");
00696   CALL_AND_TEST("''", 2, buf, 5, 5, "''''");
00697   CALL_AND_TEST("a'", 2, buf, 5, 4, "'a'");
00698   CALL_AND_TEST("'a", 2, buf, 5, 5, "''''");
00699   CALL_AND_TEST("ab", 2, buf, 5, 5, "'ab'");
00700   CALL_AND_TEST("abc", 3, buf, 5, 5, "'ab'");
00701 
00702   CALL_AND_TEST("ab", 2, buf, 6, 5, "'ab'");
00703 
00704   CALL_AND_TEST("a'b'c", 5, buf, 32, 10, "'a''b''c'");
00705   CALL_AND_TEST("a'b'c'", 6, buf, 32, 12, "'a''b''c'''");
00706 }
00707 
00708 #endif /* UNIV_COMPILE_TEST_FUNCS */
00709 #endif /* !UNIV_HOTBACKUP */