~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/ut/ut0mem.c

  • Committer: Brian Aker
  • Date: 2009-07-11 19:23:04 UTC
  • mfrom: (1089.1.14 merge)
  • Revision ID: brian@gaz-20090711192304-ootijyl5yf9jq9kd
Merge Brian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/************************************************************************
2
 
Memory primitives
3
 
 
4
 
(c) 1994, 1995 Innobase Oy
5
 
 
6
 
Created 5/11/1994 Heikki Tuuri
7
 
*************************************************************************/
8
 
 
9
 
#include "ut0mem.h"
10
 
 
11
 
#ifdef UNIV_NONINL
12
 
#include "ut0mem.ic"
13
 
#endif
14
 
 
15
 
#include "mem0mem.h"
16
 
#include "os0sync.h"
17
 
#include "os0thread.h"
18
 
 
19
 
/* This struct is placed first in every allocated memory block */
20
 
typedef struct ut_mem_block_struct ut_mem_block_t;
21
 
 
22
 
/* The total amount of memory currently allocated from the OS with malloc */
23
 
ulint   ut_total_allocated_memory       = 0;
24
 
 
25
 
struct ut_mem_block_struct{
26
 
        UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
27
 
                        /* mem block list node */
28
 
        ulint   size;   /* size of allocated memory */
29
 
        ulint   magic_n;
30
 
};
31
 
 
32
 
#define UT_MEM_MAGIC_N  1601650166
33
 
 
34
 
/* List of all memory blocks allocated from the operating system
35
 
with malloc */
36
 
UT_LIST_BASE_NODE_T(ut_mem_block_t)   ut_mem_block_list;
37
 
 
38
 
os_fast_mutex_t ut_list_mutex;  /* this protects the list */
39
 
 
40
 
ibool  ut_mem_block_list_inited = FALSE;
41
 
 
42
 
ulint*  ut_mem_null_ptr = NULL;
43
 
 
44
 
/**************************************************************************
45
 
Initializes the mem block list at database startup. */
46
 
static
47
 
void
48
 
ut_mem_block_list_init(void)
49
 
/*========================*/
50
 
{
51
 
        os_fast_mutex_init(&ut_list_mutex);
52
 
        UT_LIST_INIT(ut_mem_block_list);
53
 
        ut_mem_block_list_inited = TRUE;
54
 
}
55
 
 
56
 
/**************************************************************************
57
 
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
58
 
defined and set_to_zero is TRUE. */
59
 
 
60
 
void*
61
 
ut_malloc_low(
62
 
/*==========*/
63
 
                                /* out, own: allocated memory */
64
 
        ulint   n,              /* in: number of bytes to allocate */
65
 
        ibool   set_to_zero,    /* in: TRUE if allocated memory should be
66
 
                                set to zero if UNIV_SET_MEM_TO_ZERO is
67
 
                                defined */
68
 
        ibool   assert_on_error)/* in: if TRUE, we crash mysqld if the
69
 
                                memory cannot be allocated */
70
 
{
71
 
        ulint   retry_count     = 0;
72
 
        void*   ret;
73
 
 
74
 
        ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
75
 
 
76
 
        if (!ut_mem_block_list_inited) {
77
 
                ut_mem_block_list_init();
78
 
        }
79
 
retry:
80
 
        os_fast_mutex_lock(&ut_list_mutex);
81
 
 
82
 
        ret = malloc(n + sizeof(ut_mem_block_t));
83
 
 
84
 
        if (ret == NULL && retry_count < 60) {
85
 
                if (retry_count == 0) {
86
 
                        ut_print_timestamp(stderr);
87
 
 
88
 
                        fprintf(stderr,
89
 
                                "  InnoDB: Error: cannot allocate"
90
 
                                " %lu bytes of\n"
91
 
                                "InnoDB: memory with malloc!"
92
 
                                " Total allocated memory\n"
93
 
                                "InnoDB: by InnoDB %lu bytes."
94
 
                                " Operating system errno: %lu\n"
95
 
                                "InnoDB: Check if you should"
96
 
                                " increase the swap file or\n"
97
 
                                "InnoDB: ulimits of your operating system.\n"
98
 
                                "InnoDB: On FreeBSD check you"
99
 
                                " have compiled the OS with\n"
100
 
                                "InnoDB: a big enough maximum process size.\n"
101
 
                                "InnoDB: Note that in most 32-bit"
102
 
                                " computers the process\n"
103
 
                                "InnoDB: memory space is limited"
104
 
                                " to 2 GB or 4 GB.\n"
105
 
                                "InnoDB: We keep retrying"
106
 
                                " the allocation for 60 seconds...\n",
107
 
                                (ulong) n, (ulong) ut_total_allocated_memory,
108
 
#ifdef __WIN__
109
 
                                (ulong) GetLastError()
110
 
#else
111
 
                                (ulong) errno
112
 
#endif
113
 
                                );
114
 
                }
115
 
 
116
 
                os_fast_mutex_unlock(&ut_list_mutex);
117
 
 
118
 
                /* Sleep for a second and retry the allocation; maybe this is
119
 
                just a temporary shortage of memory */
120
 
 
121
 
                os_thread_sleep(1000000);
122
 
 
123
 
                retry_count++;
124
 
 
125
 
                goto retry;
126
 
        }
127
 
 
128
 
        if (ret == NULL) {
129
 
                /* Flush stderr to make more probable that the error
130
 
                message gets in the error file before we generate a seg
131
 
                fault */
132
 
 
133
 
                fflush(stderr);
134
 
 
135
 
                os_fast_mutex_unlock(&ut_list_mutex);
136
 
 
137
 
                /* Make an intentional seg fault so that we get a stack
138
 
                trace */
139
 
                /* Intentional segfault on NetWare causes an abend. Avoid this
140
 
                by graceful exit handling in ut_a(). */
141
 
                if (assert_on_error) {
142
 
                        ut_print_timestamp(stderr);
143
 
 
144
 
                        fprintf(stderr,
145
 
                                "  InnoDB: We now intentionally"
146
 
                                " generate a seg fault so that\n"
147
 
                                "InnoDB: on Linux we get a stack trace.\n");
148
 
 
149
 
                        if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
150
 
                } else {
151
 
                        return(NULL);
152
 
                }
153
 
        }
154
 
 
155
 
        if (set_to_zero) {
156
 
#ifdef UNIV_SET_MEM_TO_ZERO
157
 
                memset(ret, '\0', n + sizeof(ut_mem_block_t));
158
 
#endif
159
 
        }
160
 
 
161
 
        UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
162
 
 
163
 
        ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
164
 
        ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
165
 
 
166
 
        ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
167
 
 
168
 
        UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
169
 
                          ((ut_mem_block_t*)ret));
170
 
        os_fast_mutex_unlock(&ut_list_mutex);
171
 
 
172
 
        return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
173
 
}
174
 
 
175
 
/**************************************************************************
176
 
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
177
 
defined. */
178
 
 
179
 
void*
180
 
ut_malloc(
181
 
/*======*/
182
 
                        /* out, own: allocated memory */
183
 
        ulint   n)      /* in: number of bytes to allocate */
184
 
{
185
 
        return(ut_malloc_low(n, TRUE, TRUE));
186
 
}
187
 
 
188
 
/**************************************************************************
189
 
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
190
 
out. It cannot be used if we want to return an error message. Prints to
191
 
stderr a message if fails. */
192
 
 
193
 
ibool
194
 
ut_test_malloc(
195
 
/*===========*/
196
 
                        /* out: TRUE if succeeded */
197
 
        ulint   n)      /* in: try to allocate this many bytes */
198
 
{
199
 
        void*   ret;
200
 
 
201
 
        ret = malloc(n);
202
 
 
203
 
        if (ret == NULL) {
204
 
                ut_print_timestamp(stderr);
205
 
                fprintf(stderr,
206
 
                        "  InnoDB: Error: cannot allocate"
207
 
                        " %lu bytes of memory for\n"
208
 
                        "InnoDB: a BLOB with malloc! Total allocated memory\n"
209
 
                        "InnoDB: by InnoDB %lu bytes."
210
 
                        " Operating system errno: %d\n"
211
 
                        "InnoDB: Check if you should increase"
212
 
                        " the swap file or\n"
213
 
                        "InnoDB: ulimits of your operating system.\n"
214
 
                        "InnoDB: On FreeBSD check you have"
215
 
                        " compiled the OS with\n"
216
 
                        "InnoDB: a big enough maximum process size.\n",
217
 
                        (ulong) n,
218
 
                        (ulong) ut_total_allocated_memory,
219
 
                        (int) errno);
220
 
                return(FALSE);
221
 
        }
222
 
 
223
 
        free(ret);
224
 
 
225
 
        return(TRUE);
226
 
}
227
 
 
228
 
/**************************************************************************
229
 
Frees a memory block allocated with ut_malloc. */
230
 
 
231
 
void
232
 
ut_free(
233
 
/*====*/
234
 
        void* ptr)  /* in, own: memory block */
235
 
{
236
 
        ut_mem_block_t* block;
237
 
 
238
 
        block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
239
 
 
240
 
        os_fast_mutex_lock(&ut_list_mutex);
241
 
 
242
 
        ut_a(block->magic_n == UT_MEM_MAGIC_N);
243
 
        ut_a(ut_total_allocated_memory >= block->size);
244
 
 
245
 
        ut_total_allocated_memory -= block->size;
246
 
 
247
 
        UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
248
 
        free(block);
249
 
 
250
 
        os_fast_mutex_unlock(&ut_list_mutex);
251
 
}
252
 
 
253
 
/**************************************************************************
254
 
Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
255
 
use this function because the allocation functions in mem0mem.h are the
256
 
recommended ones in InnoDB.
257
 
 
258
 
man realloc in Linux, 2004:
259
 
 
260
 
       realloc()  changes the size of the memory block pointed to
261
 
       by ptr to size bytes.  The contents will be  unchanged  to
262
 
       the minimum of the old and new sizes; newly allocated mem�
263
 
       ory will be uninitialized.  If ptr is NULL,  the  call  is
264
 
       equivalent  to malloc(size); if size is equal to zero, the
265
 
       call is equivalent to free(ptr).  Unless ptr is  NULL,  it
266
 
       must  have  been  returned by an earlier call to malloc(),
267
 
       calloc() or realloc().
268
 
 
269
 
RETURN VALUE
270
 
       realloc() returns a pointer to the newly allocated memory,
271
 
       which is suitably aligned for any kind of variable and may
272
 
       be different from ptr, or NULL if the  request  fails.  If
273
 
       size  was equal to 0, either NULL or a pointer suitable to
274
 
       be passed to free() is returned.  If realloc()  fails  the
275
 
       original  block  is  left  untouched  - it is not freed or
276
 
       moved. */
277
 
 
278
 
void*
279
 
ut_realloc(
280
 
/*=======*/
281
 
                        /* out, own: pointer to new mem block or NULL */
282
 
        void*   ptr,    /* in: pointer to old block or NULL */
283
 
        ulint   size)   /* in: desired size */
284
 
{
285
 
        ut_mem_block_t* block;
286
 
        ulint           old_size;
287
 
        ulint           min_size;
288
 
        void*           new_ptr;
289
 
 
290
 
        if (ptr == NULL) {
291
 
 
292
 
                return(ut_malloc(size));
293
 
        }
294
 
 
295
 
        if (size == 0) {
296
 
                ut_free(ptr);
297
 
 
298
 
                return(NULL);
299
 
        }
300
 
 
301
 
        block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
302
 
 
303
 
        ut_a(block->magic_n == UT_MEM_MAGIC_N);
304
 
 
305
 
        old_size = block->size - sizeof(ut_mem_block_t);
306
 
 
307
 
        if (size < old_size) {
308
 
                min_size = size;
309
 
        } else {
310
 
                min_size = old_size;
311
 
        }
312
 
 
313
 
        new_ptr = ut_malloc(size);
314
 
 
315
 
        if (new_ptr == NULL) {
316
 
 
317
 
                return(NULL);
318
 
        }
319
 
 
320
 
        /* Copy the old data from ptr */
321
 
        ut_memcpy(new_ptr, ptr, min_size);
322
 
 
323
 
        ut_free(ptr);
324
 
 
325
 
        return(new_ptr);
326
 
}
327
 
 
328
 
/**************************************************************************
329
 
Frees in shutdown all allocated memory not freed yet. */
330
 
 
331
 
void
332
 
ut_free_all_mem(void)
333
 
/*=================*/
334
 
{
335
 
        ut_mem_block_t* block;
336
 
 
337
 
        os_fast_mutex_free(&ut_list_mutex);
338
 
 
339
 
        while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
340
 
 
341
 
                ut_a(block->magic_n == UT_MEM_MAGIC_N);
342
 
                ut_a(ut_total_allocated_memory >= block->size);
343
 
 
344
 
                ut_total_allocated_memory -= block->size;
345
 
 
346
 
                UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
347
 
                free(block);
348
 
        }
349
 
 
350
 
        if (ut_total_allocated_memory != 0) {
351
 
                fprintf(stderr,
352
 
                        "InnoDB: Warning: after shutdown"
353
 
                        " total allocated memory is %lu\n",
354
 
                        (ulong) ut_total_allocated_memory);
355
 
        }
356
 
}
357
 
 
358
 
/**************************************************************************
359
 
Copies up to size - 1 characters from the NUL-terminated string src to
360
 
dst, NUL-terminating the result. Returns strlen(src), so truncation
361
 
occurred if the return value >= size. */
362
 
 
363
 
ulint
364
 
ut_strlcpy(
365
 
/*=======*/
366
 
                                /* out: strlen(src) */
367
 
        char*           dst,    /* in: destination buffer */
368
 
        const char*     src,    /* in: source buffer */
369
 
        ulint           size)   /* in: size of destination buffer */
370
 
{
371
 
        ulint   src_size = strlen(src);
372
 
 
373
 
        if (size != 0) {
374
 
                ulint   n = ut_min(src_size, size - 1);
375
 
 
376
 
                memcpy(dst, src, n);
377
 
                dst[n] = '\0';
378
 
        }
379
 
 
380
 
        return(src_size);
381
 
}
382
 
 
383
 
/**************************************************************************
384
 
Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
385
 
(size - 1) bytes of src, not the first. */
386
 
 
387
 
ulint
388
 
ut_strlcpy_rev(
389
 
/*===========*/
390
 
                                /* out: strlen(src) */
391
 
        char*           dst,    /* in: destination buffer */
392
 
        const char*     src,    /* in: source buffer */
393
 
        ulint           size)   /* in: size of destination buffer */
394
 
{
395
 
        ulint   src_size = strlen(src);
396
 
 
397
 
        if (size != 0) {
398
 
                ulint   n = ut_min(src_size, size - 1);
399
 
 
400
 
                memcpy(dst, src + src_size - n, n + 1);
401
 
        }
402
 
 
403
 
        return(src_size);
404
 
}
405
 
 
406
 
/**************************************************************************
407
 
Make a quoted copy of a NUL-terminated string.  Leading and trailing
408
 
quotes will not be included; only embedded quotes will be escaped.
409
 
See also ut_strlenq() and ut_memcpyq(). */
410
 
 
411
 
char*
412
 
ut_strcpyq(
413
 
/*=======*/
414
 
                                /* out: pointer to end of dest */
415
 
        char*           dest,   /* in: output buffer */
416
 
        char            q,      /* in: the quote character */
417
 
        const char*     src)    /* in: null-terminated string */
418
 
{
419
 
        while (*src) {
420
 
                if ((*dest++ = *src++) == q) {
421
 
                        *dest++ = q;
422
 
                }
423
 
        }
424
 
 
425
 
        return(dest);
426
 
}
427
 
 
428
 
/**************************************************************************
429
 
Make a quoted copy of a fixed-length string.  Leading and trailing
430
 
quotes will not be included; only embedded quotes will be escaped.
431
 
See also ut_strlenq() and ut_strcpyq(). */
432
 
 
433
 
char*
434
 
ut_memcpyq(
435
 
/*=======*/
436
 
                                /* out: pointer to end of dest */
437
 
        char*           dest,   /* in: output buffer */
438
 
        char            q,      /* in: the quote character */
439
 
        const char*     src,    /* in: string to be quoted */
440
 
        ulint           len)    /* in: length of src */
441
 
{
442
 
        const char*     srcend = src + len;
443
 
 
444
 
        while (src < srcend) {
445
 
                if ((*dest++ = *src++) == q) {
446
 
                        *dest++ = q;
447
 
                }
448
 
        }
449
 
 
450
 
        return(dest);
451
 
}
452
 
 
453
 
/**************************************************************************
454
 
Return the number of times s2 occurs in s1. Overlapping instances of s2
455
 
are only counted once. */
456
 
 
457
 
ulint
458
 
ut_strcount(
459
 
/*========*/
460
 
                                /* out: the number of times s2 occurs in s1 */
461
 
        const char*     s1,     /* in: string to search in */
462
 
        const char*     s2)     /* in: string to search for */
463
 
{
464
 
        ulint   count = 0;
465
 
        ulint   len = strlen(s2);
466
 
 
467
 
        if (len == 0) {
468
 
 
469
 
                return(0);
470
 
        }
471
 
 
472
 
        for (;;) {
473
 
                s1 = strstr(s1, s2);
474
 
 
475
 
                if (!s1) {
476
 
 
477
 
                        break;
478
 
                }
479
 
 
480
 
                count++;
481
 
                s1 += len;
482
 
        }
483
 
 
484
 
        return(count);
485
 
}
486
 
 
487
 
/**************************************************************************
488
 
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
489
 
are only replaced once. */
490
 
 
491
 
char *
492
 
ut_strreplace(
493
 
/*==========*/
494
 
                                /* out, own: modified string, must be
495
 
                                freed with mem_free() */
496
 
        const char*     str,    /* in: string to operate on */
497
 
        const char*     s1,     /* in: string to replace */
498
 
        const char*     s2)     /* in: string to replace s1 with */
499
 
{
500
 
        char*           new_str;
501
 
        char*           ptr;
502
 
        const char*     str_end;
503
 
        ulint           str_len = strlen(str);
504
 
        ulint           s1_len = strlen(s1);
505
 
        ulint           s2_len = strlen(s2);
506
 
        ulint           count = 0;
507
 
        int             len_delta = (int)s2_len - (int)s1_len;
508
 
 
509
 
        str_end = str + str_len;
510
 
 
511
 
        if (len_delta <= 0) {
512
 
                len_delta = 0;
513
 
        } else {
514
 
                count = ut_strcount(str, s1);
515
 
        }
516
 
 
517
 
        new_str = mem_alloc(str_len + count * len_delta + 1);
518
 
        ptr = new_str;
519
 
 
520
 
        while (str) {
521
 
                const char*     next = strstr(str, s1);
522
 
 
523
 
                if (!next) {
524
 
                        next = str_end;
525
 
                }
526
 
 
527
 
                memcpy(ptr, str, next - str);
528
 
                ptr += next - str;
529
 
 
530
 
                if (next == str_end) {
531
 
 
532
 
                        break;
533
 
                }
534
 
 
535
 
                memcpy(ptr, s2, s2_len);
536
 
                ptr += s2_len;
537
 
 
538
 
                str = next + s1_len;
539
 
        }
540
 
 
541
 
        *ptr = '\0';
542
 
 
543
 
        return(new_str);
544
 
}