00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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);
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
00163
00164
00165 os_thread_sleep(1000000);
00166
00167 retry_count++;
00168
00169 goto retry;
00170 }
00171
00172 if (ret == NULL) {
00173
00174
00175
00176
00177 fflush(stderr);
00178
00179 os_fast_mutex_unlock(&ut_list_mutex);
00180
00181
00182
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
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
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
00242 return(malloc(n));
00243 #endif
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
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
00322 free(ptr);
00323 #endif
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
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
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
00709 #endif