~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/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
 
 
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
 
#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(NULL, 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
 
        mutex_enter(&(mem_comm_pool->mutex));
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
 
        mutex_exit(&(mem_comm_pool->mutex));
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
 
        if (UNIV_UNLIKELY(heap == NULL)) {
387
 
                /* This is the first block of the heap. The field
388
 
                total_size should be initialized here */
389
 
                block->total_size = len;
390
 
        } else {
391
 
                /* Not the first allocation for the heap. This block's
392
 
                total_length field should be set to undefined. */
393
 
                ut_d(block->total_size = ULINT_UNDEFINED);
394
 
                UNIV_MEM_INVALID(&block->total_size,
395
 
                                 sizeof block->total_size);
396
 
 
397
 
                heap->total_size += len;
398
 
        }
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
 
@return created block, NULL if did not succeed (only possible for
408
 
MEM_HEAP_BTR_SEARCH type heaps) */
409
 
UNIV_INTERN
410
 
mem_block_t*
411
 
mem_heap_add_block(
412
 
/*===============*/
413
 
        mem_heap_t*     heap,   /*!< in: memory heap */
414
 
        ulint           n)      /*!< in: number of bytes user needs */
415
 
{
416
 
        mem_block_t*    block;
417
 
        mem_block_t*    new_block;
418
 
        ulint           new_size;
419
 
 
420
 
        ut_ad(mem_heap_check(heap));
421
 
 
422
 
        block = UT_LIST_GET_LAST(heap->base);
423
 
 
424
 
        /* We have to allocate a new block. The size is always at least
425
 
        doubled until the standard size is reached. After that the size
426
 
        stays the same, except in cases where the caller needs more space. */
427
 
 
428
 
        new_size = 2 * mem_block_get_len(block);
429
 
 
430
 
        if (heap->type != MEM_HEAP_DYNAMIC) {
431
 
                /* From the buffer pool we allocate buffer frames */
432
 
                ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
433
 
 
434
 
                if (new_size > MEM_MAX_ALLOC_IN_BUF) {
435
 
                        new_size = MEM_MAX_ALLOC_IN_BUF;
436
 
                }
437
 
        } else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
438
 
 
439
 
                new_size = MEM_BLOCK_STANDARD_SIZE;
440
 
        }
441
 
 
442
 
        if (new_size < n) {
443
 
                new_size = n;
444
 
        }
445
 
 
446
 
        new_block = mem_heap_create_block(heap, new_size, heap->type,
447
 
                                          heap->file_name, heap->line);
448
 
        if (new_block == NULL) {
449
 
 
450
 
                return(NULL);
451
 
        }
452
 
 
453
 
        /* Add the new block as the last block */
454
 
 
455
 
        UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
456
 
 
457
 
        return(new_block);
458
 
}
459
 
 
460
 
/******************************************************************//**
461
 
Frees a block from a memory heap. */
462
 
UNIV_INTERN
463
 
void
464
 
mem_heap_block_free(
465
 
/*================*/
466
 
        mem_heap_t*     heap,   /*!< in: heap */
467
 
        mem_block_t*    block)  /*!< in: block to free */
468
 
{
469
 
        ulint           type;
470
 
        ulint           len;
471
 
#ifndef UNIV_HOTBACKUP
472
 
        buf_block_t*    buf_block       = block->buf_block;
473
 
#endif /* !UNIV_HOTBACKUP */
474
 
 
475
 
        if (block->magic_n != MEM_BLOCK_MAGIC_N) {
476
 
                mem_analyze_corruption(block);
477
 
        }
478
 
 
479
 
        UT_LIST_REMOVE(list, heap->base, block);
480
 
 
481
 
#ifdef MEM_PERIODIC_CHECK
482
 
        mutex_enter(&(mem_comm_pool->mutex));
483
 
 
484
 
        UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
485
 
 
486
 
        mutex_exit(&(mem_comm_pool->mutex));
487
 
#endif
488
 
 
489
 
        ut_ad(heap->total_size >= block->len);
490
 
        heap->total_size -= block->len;
491
 
 
492
 
        type = heap->type;
493
 
        len = block->len;
494
 
        block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
495
 
 
496
 
#ifndef UNIV_HOTBACKUP
497
 
#ifdef UNIV_MEM_DEBUG
498
 
        /* In the debug version we set the memory to a random combination
499
 
        of hex 0xDE and 0xAD. */
500
 
 
501
 
        mem_erase_buf((byte*)block, len);
502
 
#else /* UNIV_MEM_DEBUG */
503
 
        UNIV_MEM_ASSERT_AND_FREE(block, len);
504
 
#endif /* UNIV_MEM_DEBUG */
505
 
 
506
 
        if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
507
 
 
508
 
                ut_ad(!buf_block);
509
 
                mem_area_free(block, mem_comm_pool);
510
 
        } else {
511
 
                ut_ad(type & MEM_HEAP_BUFFER);
512
 
 
513
 
                buf_block_free(buf_block);
514
 
        }
515
 
#else /* !UNIV_HOTBACKUP */
516
 
#ifdef UNIV_MEM_DEBUG
517
 
        /* In the debug version we set the memory to a random
518
 
        combination of hex 0xDE and 0xAD. */
519
 
 
520
 
        mem_erase_buf((byte*)block, len);
521
 
#else /* UNIV_MEM_DEBUG */
522
 
        UNIV_MEM_ASSERT_AND_FREE(block, len);
523
 
#endif /* UNIV_MEM_DEBUG */
524
 
        ut_free(block);
525
 
#endif /* !UNIV_HOTBACKUP */
526
 
}
527
 
 
528
 
#ifndef UNIV_HOTBACKUP
529
 
/******************************************************************//**
530
 
Frees the free_block field from a memory heap. */
531
 
UNIV_INTERN
532
 
void
533
 
mem_heap_free_block_free(
534
 
/*=====================*/
535
 
        mem_heap_t*     heap)   /*!< in: heap */
536
 
{
537
 
        if (UNIV_LIKELY_NULL(heap->free_block)) {
538
 
 
539
 
                buf_block_free(heap->free_block);
540
 
 
541
 
                heap->free_block = NULL;
542
 
        }
543
 
}
544
 
#endif /* !UNIV_HOTBACKUP */
545
 
 
546
 
#ifdef MEM_PERIODIC_CHECK
547
 
/******************************************************************//**
548
 
Goes through the list of all allocated mem blocks, checks their magic
549
 
numbers, and reports possible corruption. */
550
 
UNIV_INTERN
551
 
void
552
 
mem_validate_all_blocks(void)
553
 
/*=========================*/
554
 
{
555
 
        mem_block_t*    block;
556
 
 
557
 
        mutex_enter(&(mem_comm_pool->mutex));
558
 
 
559
 
        block = UT_LIST_GET_FIRST(mem_block_list);
560
 
 
561
 
        while (block) {
562
 
                if (block->magic_n != MEM_BLOCK_MAGIC_N) {
563
 
                        mem_analyze_corruption(block);
564
 
                }
565
 
 
566
 
                block = UT_LIST_GET_NEXT(mem_block_list, block);
567
 
        }
568
 
 
569
 
        mutex_exit(&(mem_comm_pool->mutex));
570
 
}
571
 
#endif