~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-08-05 19:01:20 UTC
  • mto: (266.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 266.
  • Revision ID: monty@inaugust.com-20080805190120-tsuziqz2mfqcw7pe
Removed libmysyslt.la, made mysys a noinst_ and made everything use it. It's
not a standalone lib, there's no reason to pretend otherwise.

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
}