~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

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