~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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