~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/mem/mem0mem.c

Removing global errbuff and cleaning up two remaining instances that referenced it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
5
This program is free software; you can redistribute it and/or modify it under
 
6
the terms of the GNU General Public License as published by the Free Software
 
7
Foundation; version 2 of the License.
 
8
 
 
9
This program is distributed in the hope that it will be useful, but WITHOUT
 
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
12
 
 
13
You should have received a copy of the GNU General Public License along with
 
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/************************************************************************
 
20
The memory management
 
21
 
 
22
Created 6/9/1994 Heikki Tuuri
 
23
*************************************************************************/
 
24
 
 
25
#include "mem0mem.h"
 
26
#ifdef UNIV_NONINL
 
27
#include "mem0mem.ic"
 
28
#endif
 
29
 
 
30
#include "buf0buf.h"
 
31
#include "srv0srv.h"
 
32
#include "mem0dbg.c"
 
33
#include <stdarg.h>
 
34
 
 
35
/*
 
36
                        THE MEMORY MANAGEMENT
 
37
                        =====================
 
38
 
 
39
The basic element of the memory management is called a memory
 
40
heap. A memory heap is conceptually a
 
41
stack from which memory can be allocated. The stack may grow infinitely.
 
42
The top element of the stack may be freed, or
 
43
the whole stack can be freed at one time. The advantage of the
 
44
memory heap concept is that we can avoid using the malloc and free
 
45
functions of C which are quite expensive, for example, on the Solaris + GCC
 
46
system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
 
47
on Win NT + 100MHz Pentium, 2.5 microseconds.
 
48
When we use a memory heap,
 
49
we can allocate larger blocks of memory at a time and thus
 
50
reduce overhead. Slightly more efficient the method is when we
 
51
allocate the memory from the index page buffer pool, as we can
 
52
claim a new page fast. This is called buffer allocation.
 
53
When we allocate the memory from the dynamic memory of the
 
54
C environment, that is called dynamic allocation.
 
55
 
 
56
The default way of operation of the memory heap is the following.
 
57
First, when the heap is created, an initial block of memory is
 
58
allocated. In dynamic allocation this may be about 50 bytes.
 
59
If more space is needed, additional blocks are allocated
 
60
and they are put into a linked list.
 
61
After the initial block, each allocated block is twice the size of the
 
62
previous, until a threshold is attained, after which the sizes
 
63
of the blocks stay the same. An exception is, of course, the case
 
64
where the caller requests a memory buffer whose size is
 
65
bigger than the threshold. In that case a block big enough must
 
66
be allocated.
 
67
 
 
68
The heap is physically arranged so that if the current block
 
69
becomes full, a new block is allocated and always inserted in the
 
70
chain of blocks as the last block.
 
71
 
 
72
In the debug version of the memory management, all the allocated
 
73
heaps are kept in a list (which is implemented as a hash table).
 
74
Thus we can notice if the caller tries to free an already freed
 
75
heap. In addition, each buffer given to the caller contains
 
76
start field at the start and a trailer field at the end of the buffer.
 
77
 
 
78
The start field has the following content:
 
79
A. sizeof(ulint) bytes of field length (in the standard byte order)
 
80
B. sizeof(ulint) bytes of check field (a random number)
 
81
 
 
82
The trailer field contains:
 
83
A. sizeof(ulint) bytes of check field (the same random number as at the start)
 
84
 
 
85
Thus we can notice if something has been copied over the
 
86
borders of the buffer, which is illegal.
 
87
The memory in the buffers is initialized to a random byte sequence.
 
88
After freeing, all the blocks in the heap are set to random bytes
 
89
to help us discover errors which result from the use of
 
90
buffers in an already freed heap. */
 
91
 
 
92
#ifdef MEM_PERIODIC_CHECK
 
93
 
 
94
ibool                                   mem_block_list_inited;
 
95
/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
 
96
UT_LIST_BASE_NODE_T(mem_block_t)        mem_block_list;
 
97
 
 
98
#endif
 
99
 
 
100
/**************************************************************************
 
101
Duplicates a NUL-terminated string, allocated from a memory heap. */
 
102
UNIV_INTERN
 
103
char*
 
104
mem_heap_strdup(
 
105
/*============*/
 
106
                                /* out, own: a copy of the string */
 
107
        mem_heap_t*     heap,   /* in: memory heap where string is allocated */
 
108
        const char*     str)    /* in: string to be copied */
 
109
{
 
110
        return(mem_heap_dup(heap, str, strlen(str) + 1));
 
111
}
 
112
 
 
113
/**************************************************************************
 
114
Duplicate a block of data, allocated from a memory heap. */
 
115
UNIV_INTERN
 
116
void*
 
117
mem_heap_dup(
 
118
/*=========*/
 
119
                                /* out, own: a copy of the data */
 
120
        mem_heap_t*     heap,   /* in: memory heap where copy is allocated */
 
121
        const void*     data,   /* in: data to be copied */
 
122
        ulint           len)    /* in: length of data, in bytes */
 
123
{
 
124
        return(memcpy(mem_heap_alloc(heap, len), data, len));
 
125
}
 
126
 
 
127
/**************************************************************************
 
128
Concatenate two memory blocks and return the result, using a memory heap. */
 
129
UNIV_INTERN
 
130
void*
 
131
mem_heap_cat(
 
132
/*=========*/
 
133
                                /* out, own: the result */
 
134
        mem_heap_t*     heap,   /* in: memory heap where result is allocated */
 
135
        const void*     b1,     /* in: block 1 */
 
136
        ulint           len1,   /* in: length of b1, in bytes */
 
137
        const void*     b2,     /* in: block 2 */
 
138
        ulint           len2)   /* in: length of b2, in bytes */
 
139
{
 
140
        void*   res = mem_heap_alloc(heap, len1 + len2);
 
141
 
 
142
        memcpy(res, b1, len1);
 
143
        memcpy((char*)res + len1, b2, len2);
 
144
 
 
145
        return(res);
 
146
}
 
147
 
 
148
/**************************************************************************
 
149
Concatenate two strings and return the result, using a memory heap. */
 
150
UNIV_INTERN
 
151
char*
 
152
mem_heap_strcat(
 
153
/*============*/
 
154
                                /* out, own: the result */
 
155
        mem_heap_t*     heap,   /* in: memory heap where string is allocated */
 
156
        const char*     s1,     /* in: string 1 */
 
157
        const char*     s2)     /* in: string 2 */
 
158
{
 
159
        char*   s;
 
160
        ulint   s1_len = strlen(s1);
 
161
        ulint   s2_len = strlen(s2);
 
162
 
 
163
        s = mem_heap_alloc(heap, s1_len + s2_len + 1);
 
164
 
 
165
        memcpy(s, s1, s1_len);
 
166
        memcpy(s + s1_len, s2, s2_len);
 
167
 
 
168
        s[s1_len + s2_len] = '\0';
 
169
 
 
170
        return(s);
 
171
}
 
172
 
 
173
 
 
174
/********************************************************************
 
175
Helper function for mem_heap_printf. */
 
176
static
 
177
ulint
 
178
mem_heap_printf_low(
 
179
/*================*/
 
180
                                /* out: length of formatted string,
 
181
                                including terminating NUL */
 
182
        char*           buf,    /* in/out: buffer to store formatted string
 
183
                                in, or NULL to just calculate length */
 
184
        const char*     format, /* in: format string */
 
185
        va_list         ap)     /* in: arguments */
 
186
{
 
187
        ulint           len = 0;
 
188
 
 
189
        while (*format) {
 
190
 
 
191
                /* Does this format specifier have the 'l' length modifier. */
 
192
                ibool   is_long = FALSE;
 
193
 
 
194
                /* Length of one parameter. */
 
195
                size_t  plen;
 
196
 
 
197
                if (*format++ != '%') {
 
198
                        /* Non-format character. */
 
199
 
 
200
                        len++;
 
201
 
 
202
                        if (buf) {
 
203
                                *buf++ = *(format - 1);
 
204
                        }
 
205
 
 
206
                        continue;
 
207
                }
 
208
 
 
209
                if (*format == 'l') {
 
210
                        is_long = TRUE;
 
211
                        format++;
 
212
                }
 
213
 
 
214
                switch (*format++) {
 
215
                case 's':
 
216
                        /* string */
 
217
                        {
 
218
                                char*   s = va_arg(ap, char*);
 
219
 
 
220
                                /* "%ls" is a non-sensical format specifier. */
 
221
                                ut_a(!is_long);
 
222
 
 
223
                                plen = strlen(s);
 
224
                                len += plen;
 
225
 
 
226
                                if (buf) {
 
227
                                        memcpy(buf, s, plen);
 
228
                                        buf += plen;
 
229
                                }
 
230
                        }
 
231
 
 
232
                        break;
 
233
 
 
234
                case 'u':
 
235
                        /* unsigned int */
 
236
                        {
 
237
                                char            tmp[32];
 
238
                                unsigned long   val;
 
239
 
 
240
                                /* We only support 'long' values for now. */
 
241
                                ut_a(is_long);
 
242
 
 
243
                                val = va_arg(ap, unsigned long);
 
244
 
 
245
                                plen = sprintf(tmp, "%lu", val);
 
246
                                len += plen;
 
247
 
 
248
                                if (buf) {
 
249
                                        memcpy(buf, tmp, plen);
 
250
                                        buf += plen;
 
251
                                }
 
252
                        }
 
253
 
 
254
                        break;
 
255
 
 
256
                case '%':
 
257
 
 
258
                        /* "%l%" is a non-sensical format specifier. */
 
259
                        ut_a(!is_long);
 
260
 
 
261
                        len++;
 
262
 
 
263
                        if (buf) {
 
264
                                *buf++ = '%';
 
265
                        }
 
266
 
 
267
                        break;
 
268
 
 
269
                default:
 
270
                        ut_error;
 
271
                }
 
272
        }
 
273
 
 
274
        /* For the NUL character. */
 
275
        len++;
 
276
 
 
277
        if (buf) {
 
278
                *buf = '\0';
 
279
        }
 
280
 
 
281
        return(len);
 
282
}
 
283
 
 
284
/********************************************************************
 
285
A simple (s)printf replacement that dynamically allocates the space for the
 
286
formatted string from the given heap. This supports a very limited set of
 
287
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
 
288
required for the 'u' type). */
 
289
UNIV_INTERN
 
290
char*
 
291
mem_heap_printf(
 
292
/*============*/
 
293
                                /* out: heap-allocated formatted string */
 
294
        mem_heap_t*     heap,   /* in: memory heap */
 
295
        const char*     format, /* in: format string */
 
296
        ...)
 
297
{
 
298
        va_list         ap;
 
299
        char*           str;
 
300
        ulint           len;
 
301
 
 
302
        /* Calculate length of string */
 
303
        len = 0;
 
304
        va_start(ap, format);
 
305
        len = mem_heap_printf_low(NULL, format, ap);
 
306
        va_end(ap);
 
307
 
 
308
        /* Now create it for real. */
 
309
        str = mem_heap_alloc(heap, len);
 
310
        va_start(ap, format);
 
311
        mem_heap_printf_low(str, format, ap);
 
312
        va_end(ap);
 
313
 
 
314
        return(str);
 
315
}
 
316
 
 
317
/*******************************************************************
 
318
Creates a memory heap block where data can be allocated. */
 
319
UNIV_INTERN
 
320
mem_block_t*
 
321
mem_heap_create_block(
 
322
/*==================*/
 
323
                                /* out, own: memory heap block, NULL if
 
324
                                did not succeed (only possible for
 
325
                                MEM_HEAP_BTR_SEARCH type heaps) */
 
326
        mem_heap_t*     heap,   /* in: memory heap or NULL if first block
 
327
                                should be created */
 
328
        ulint           n,      /* in: number of bytes needed for user data */
 
329
        ulint           type,   /* in: type of heap: MEM_HEAP_DYNAMIC or
 
330
                                MEM_HEAP_BUFFER */
 
331
        const char*     file_name,/* in: file name where created */
 
332
        ulint           line)   /* in: line where created */
 
333
{
 
334
        buf_block_t*    buf_block = NULL;
 
335
        mem_block_t*    block;
 
336
        ulint           len;
 
337
 
 
338
        ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
 
339
              || (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
 
340
 
 
341
        if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
 
342
                mem_analyze_corruption(heap);
 
343
        }
 
344
 
 
345
        /* In dynamic allocation, calculate the size: block header + data. */
 
346
        len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
 
347
 
 
348
        if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
 
349
 
 
350
                ut_ad(type == MEM_HEAP_DYNAMIC || n <= MEM_MAX_ALLOC_IN_BUF);
 
351
 
 
352
                block = mem_area_alloc(&len, mem_comm_pool);
 
353
        } else {
 
354
                len = UNIV_PAGE_SIZE;
 
355
 
 
356
                if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
 
357
                        /* We cannot allocate the block from the
 
358
                        buffer pool, but must get the free block from
 
359
                        the heap header free block field */
 
360
 
 
361
                        buf_block = heap->free_block;
 
362
                        heap->free_block = NULL;
 
363
 
 
364
                        if (UNIV_UNLIKELY(!buf_block)) {
 
365
 
 
366
                                return(NULL);
 
367
                        }
 
368
                } else {
 
369
                        buf_block = buf_block_alloc(0);
 
370
                }
 
371
 
 
372
                block = (mem_block_t*) buf_block->frame;
 
373
        }
 
374
 
 
375
        ut_ad(block);
 
376
        block->buf_block = buf_block;
 
377
        block->magic_n = MEM_BLOCK_MAGIC_N;
 
378
        ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
 
379
        block->line = line;
 
380
 
 
381
#ifdef MEM_PERIODIC_CHECK
 
382
        mem_pool_mutex_enter();
 
383
 
 
384
        if (!mem_block_list_inited) {
 
385
                mem_block_list_inited = TRUE;
 
386
                UT_LIST_INIT(mem_block_list);
 
387
        }
 
388
 
 
389
        UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
 
390
 
 
391
        mem_pool_mutex_exit();
 
392
#endif
 
393
        mem_block_set_len(block, len);
 
394
        mem_block_set_type(block, type);
 
395
        mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
 
396
        mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
 
397
 
 
398
        block->free_block = NULL;
 
399
 
 
400
        ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
 
401
 
 
402
        return(block);
 
403
}
 
404
 
 
405
/*******************************************************************
 
406
Adds a new block to a memory heap. */
 
407
UNIV_INTERN
 
408
mem_block_t*
 
409
mem_heap_add_block(
 
410
/*===============*/
 
411
                                /* out: created block, NULL if did not
 
412
                                succeed (only possible for
 
413
                                MEM_HEAP_BTR_SEARCH type heaps)*/
 
414
        mem_heap_t*     heap,   /* in: memory heap */
 
415
        ulint           n)      /* in: number of bytes user needs */
 
416
{
 
417
        mem_block_t*    block;
 
418
        mem_block_t*    new_block;
 
419
        ulint           new_size;
 
420
 
 
421
        ut_ad(mem_heap_check(heap));
 
422
 
 
423
        block = UT_LIST_GET_LAST(heap->base);
 
424
 
 
425
        /* We have to allocate a new block. The size is always at least
 
426
        doubled until the standard size is reached. After that the size
 
427
        stays the same, except in cases where the caller needs more space. */
 
428
 
 
429
        new_size = 2 * mem_block_get_len(block);
 
430
 
 
431
        if (heap->type != MEM_HEAP_DYNAMIC) {
 
432
                /* From the buffer pool we allocate buffer frames */
 
433
                ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
 
434
 
 
435
                if (new_size > MEM_MAX_ALLOC_IN_BUF) {
 
436
                        new_size = MEM_MAX_ALLOC_IN_BUF;
 
437
                }
 
438
        } else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
 
439
 
 
440
                new_size = MEM_BLOCK_STANDARD_SIZE;
 
441
        }
 
442
 
 
443
        if (new_size < n) {
 
444
                new_size = n;
 
445
        }
 
446
 
 
447
        new_block = mem_heap_create_block(heap, new_size, heap->type,
 
448
                                          heap->file_name, heap->line);
 
449
        if (new_block == NULL) {
 
450
 
 
451
                return(NULL);
 
452
        }
 
453
 
 
454
        /* Add the new block as the last block */
 
455
 
 
456
        UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
 
457
 
 
458
        return(new_block);
 
459
}
 
460
 
 
461
/**********************************************************************
 
462
Frees a block from a memory heap. */
 
463
UNIV_INTERN
 
464
void
 
465
mem_heap_block_free(
 
466
/*================*/
 
467
        mem_heap_t*     heap,   /* in: heap */
 
468
        mem_block_t*    block)  /* in: block to free */
 
469
{
 
470
        ulint           type;
 
471
        ulint           len;
 
472
        buf_block_t*    buf_block;
 
473
 
 
474
        if (block->magic_n != MEM_BLOCK_MAGIC_N) {
 
475
                mem_analyze_corruption(block);
 
476
        }
 
477
 
 
478
        UT_LIST_REMOVE(list, heap->base, block);
 
479
 
 
480
#ifdef MEM_PERIODIC_CHECK
 
481
        mem_pool_mutex_enter();
 
482
 
 
483
        UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
 
484
 
 
485
        mem_pool_mutex_exit();
 
486
#endif
 
487
        type = heap->type;
 
488
        len = block->len;
 
489
        buf_block = block->buf_block;
 
490
        block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
 
491
 
 
492
#ifdef UNIV_MEM_DEBUG
 
493
        /* In the debug version we set the memory to a random combination
 
494
        of hex 0xDE and 0xAD. */
 
495
 
 
496
        mem_erase_buf((byte*)block, len);
 
497
#else /* UNIV_MEM_DEBUG */
 
498
        UNIV_MEM_ASSERT_AND_FREE(block, len);
 
499
#endif /* UNIV_MEM_DEBUG */
 
500
 
 
501
        if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
 
502
 
 
503
                ut_ad(!buf_block);
 
504
                mem_area_free(block, mem_comm_pool);
 
505
        } else {
 
506
                ut_ad(type & MEM_HEAP_BUFFER);
 
507
 
 
508
                buf_block_free(buf_block);
 
509
        }
 
510
}
 
511
 
 
512
/**********************************************************************
 
513
Frees the free_block field from a memory heap. */
 
514
UNIV_INTERN
 
515
void
 
516
mem_heap_free_block_free(
 
517
/*=====================*/
 
518
        mem_heap_t*     heap)   /* in: heap */
 
519
{
 
520
        if (UNIV_LIKELY_NULL(heap->free_block)) {
 
521
 
 
522
                buf_block_free(heap->free_block);
 
523
 
 
524
                heap->free_block = NULL;
 
525
        }
 
526
}
 
527
 
 
528
#ifdef MEM_PERIODIC_CHECK
 
529
/**********************************************************************
 
530
Goes through the list of all allocated mem blocks, checks their magic
 
531
numbers, and reports possible corruption. */
 
532
UNIV_INTERN
 
533
void
 
534
mem_validate_all_blocks(void)
 
535
/*=========================*/
 
536
{
 
537
        mem_block_t*    block;
 
538
 
 
539
        mem_pool_mutex_enter();
 
540
 
 
541
        block = UT_LIST_GET_FIRST(mem_block_list);
 
542
 
 
543
        while (block) {
 
544
                if (block->magic_n != MEM_BLOCK_MAGIC_N) {
 
545
                        mem_analyze_corruption(block);
 
546
                }
 
547
 
 
548
                block = UT_LIST_GET_NEXT(mem_block_list, block);
 
549
        }
 
550
 
 
551
        mem_pool_mutex_exit();
 
552
}
 
553
#endif