~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/mem/mem0mem.cc

  • Committer: Monty Taylor
  • Date: 2008-10-16 06:32:59 UTC
  • mfrom: (518 drizzle)
  • mto: (511.1.5 codestyle)
  • mto: This revision was merged to the branch mainline in revision 521.
  • Revision ID: monty@inaugust.com-20081016063259-fwbqogq7lnezct0l
Merged with trunk.

Show diffs side-by-side

added added

removed removed

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