~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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