~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1997, 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
 
The lowest-level memory management
21
 
 
22
 
Created 5/12/1997 Heikki Tuuri
23
 
*************************************************************************/
24
 
 
25
 
#include "mem0pool.h"
26
 
#ifdef UNIV_NONINL
27
 
#include "mem0pool.ic"
28
 
#endif
29
 
 
30
 
#include "srv0srv.h"
31
 
#include "sync0sync.h"
32
 
#include "ut0mem.h"
33
 
#include "ut0lst.h"
34
 
#include "ut0byte.h"
35
 
#include "mem0mem.h"
36
 
 
37
 
/* We would like to use also the buffer frames to allocate memory. This
38
 
would be desirable, because then the memory consumption of the database
39
 
would be fixed, and we might even lock the buffer pool to the main memory.
40
 
The problem here is that the buffer management routines can themselves call
41
 
memory allocation, while the buffer pool mutex is reserved.
42
 
 
43
 
The main components of the memory consumption are:
44
 
 
45
 
1. buffer pool,
46
 
2. parsed and optimized SQL statements,
47
 
3. data dictionary cache,
48
 
4. log buffer,
49
 
5. locks for each transaction,
50
 
6. hash table for the adaptive index,
51
 
7. state and buffers for each SQL query currently being executed,
52
 
8. session for each user, and
53
 
9. stack for each OS thread.
54
 
 
55
 
Items 1 and 2 are managed by an LRU algorithm. Items 5 and 6 can potentially
56
 
consume very much memory. Items 7 and 8 should consume quite little memory,
57
 
and the OS should take care of item 9, which too should consume little memory.
58
 
 
59
 
A solution to the memory management:
60
 
 
61
 
1. the buffer pool size is set separately;
62
 
2. log buffer size is set separately;
63
 
3. the common pool size for all the other entries, except 8, is set separately.
64
 
 
65
 
Problems: we may waste memory if the common pool is set too big. Another
66
 
problem is the locks, which may take very much space in big transactions.
67
 
Then the shared pool size should be set very big. We can allow locks to take
68
 
space from the buffer pool, but the SQL optimizer is then unaware of the
69
 
usable size of the buffer pool. We could also combine the objects in the
70
 
common pool and the buffers in the buffer pool into a single LRU list and
71
 
manage it uniformly, but this approach does not take into account the parsing
72
 
and other costs unique to SQL statements.
73
 
 
74
 
The locks for a transaction can be seen as a part of the state of the
75
 
transaction. Hence, they should be stored in the common pool. We still
76
 
have the problem of a very big update transaction, for example, which
77
 
will set very many x-locks on rows, and the locks will consume a lot
78
 
of memory, say, half of the buffer pool size.
79
 
 
80
 
Another problem is what to do if we are not able to malloc a requested
81
 
block of memory from the common pool. Then we can request memory from
82
 
the operating system. If it does not help, a system error results.
83
 
 
84
 
Because 5 and 6 may potentially consume very much memory, we let them grow
85
 
into the buffer pool. We may let the locks of a transaction take frames
86
 
from the buffer pool, when the corresponding memory heap block has grown to
87
 
the size of a buffer frame. Similarly for the hash node cells of the locks,
88
 
and for the adaptive index. Thus, for each individual transaction, its locks
89
 
can occupy at most about the size of the buffer frame of memory in the common
90
 
pool, and after that its locks will grow into the buffer pool. */
91
 
 
92
 
/* Mask used to extract the free bit from area->size */
93
 
#define MEM_AREA_FREE   1
94
 
 
95
 
/* The smallest memory area total size */
96
 
#define MEM_AREA_MIN_SIZE       (2 * MEM_AREA_EXTRA_SIZE)
97
 
 
98
 
 
99
 
/* Data structure for a memory pool. The space is allocated using the buddy
100
 
algorithm, where free list i contains areas of size 2 to power i. */
101
 
struct mem_pool_struct{
102
 
        byte*           buf;            /* memory pool */
103
 
        ulint           size;           /* memory common pool size */
104
 
        ulint           reserved;       /* amount of currently allocated
105
 
                                        memory */
106
 
        mutex_t         mutex;          /* mutex protecting this struct */
107
 
        UT_LIST_BASE_NODE_T(mem_area_t)
108
 
                        free_list[64];  /* lists of free memory areas: an
109
 
                                        area is put to the list whose number
110
 
                                        is the 2-logarithm of the area size */
111
 
};
112
 
 
113
 
/* The common memory pool */
114
 
UNIV_INTERN mem_pool_t* mem_comm_pool   = NULL;
115
 
 
116
 
/* We use this counter to check that the mem pool mutex does not leak;
117
 
this is to track a strange assertion failure reported at
118
 
mysql@lists.mysql.com */
119
 
 
120
 
UNIV_INTERN ulint       mem_n_threads_inside            = 0;
121
 
 
122
 
/************************************************************************
123
 
Reserves the mem pool mutex. */
124
 
UNIV_INTERN
125
 
void
126
 
mem_pool_mutex_enter(void)
127
 
/*======================*/
128
 
{
129
 
        mutex_enter(&(mem_comm_pool->mutex));
130
 
}
131
 
 
132
 
/************************************************************************
133
 
Releases the mem pool mutex. */
134
 
UNIV_INTERN
135
 
void
136
 
mem_pool_mutex_exit(void)
137
 
/*=====================*/
138
 
{
139
 
        mutex_exit(&(mem_comm_pool->mutex));
140
 
}
141
 
 
142
 
/************************************************************************
143
 
Returns memory area size. */
144
 
UNIV_INLINE
145
 
ulint
146
 
mem_area_get_size(
147
 
/*==============*/
148
 
                                /* out: size */
149
 
        mem_area_t*     area)   /* in: area */
150
 
{
151
 
        return(area->size_and_free & ~MEM_AREA_FREE);
152
 
}
153
 
 
154
 
/************************************************************************
155
 
Sets memory area size. */
156
 
UNIV_INLINE
157
 
void
158
 
mem_area_set_size(
159
 
/*==============*/
160
 
        mem_area_t*     area,   /* in: area */
161
 
        ulint           size)   /* in: size */
162
 
{
163
 
        area->size_and_free = (area->size_and_free & MEM_AREA_FREE)
164
 
                | size;
165
 
}
166
 
 
167
 
/************************************************************************
168
 
Returns memory area free bit. */
169
 
UNIV_INLINE
170
 
ibool
171
 
mem_area_get_free(
172
 
/*==============*/
173
 
                                /* out: TRUE if free */
174
 
        mem_area_t*     area)   /* in: area */
175
 
{
176
 
#if TRUE != MEM_AREA_FREE
177
 
# error "TRUE != MEM_AREA_FREE"
178
 
#endif
179
 
        return(area->size_and_free & MEM_AREA_FREE);
180
 
}
181
 
 
182
 
/************************************************************************
183
 
Sets memory area free bit. */
184
 
UNIV_INLINE
185
 
void
186
 
mem_area_set_free(
187
 
/*==============*/
188
 
        mem_area_t*     area,   /* in: area */
189
 
        ibool           free)   /* in: free bit value */
190
 
{
191
 
#if TRUE != MEM_AREA_FREE
192
 
# error "TRUE != MEM_AREA_FREE"
193
 
#endif
194
 
        area->size_and_free = (area->size_and_free & ~MEM_AREA_FREE)
195
 
                | free;
196
 
}
197
 
 
198
 
/************************************************************************
199
 
Creates a memory pool. */
200
 
UNIV_INTERN
201
 
mem_pool_t*
202
 
mem_pool_create(
203
 
/*============*/
204
 
                        /* out: memory pool */
205
 
        ulint   size)   /* in: pool size in bytes */
206
 
{
207
 
        mem_pool_t*     pool;
208
 
        mem_area_t*     area;
209
 
        ulint           i;
210
 
        ulint           used;
211
 
 
212
 
        pool = ut_malloc(sizeof(mem_pool_t));
213
 
 
214
 
        /* We do not set the memory to zero (FALSE) in the pool,
215
 
        but only when allocated at a higher level in mem0mem.c.
216
 
        This is to avoid masking useful Purify warnings. */
217
 
 
218
 
        pool->buf = ut_malloc_low(size, FALSE, TRUE);
219
 
        pool->size = size;
220
 
 
221
 
        mutex_create(&pool->mutex, SYNC_MEM_POOL);
222
 
 
223
 
        /* Initialize the free lists */
224
 
 
225
 
        for (i = 0; i < 64; i++) {
226
 
 
227
 
                UT_LIST_INIT(pool->free_list[i]);
228
 
        }
229
 
 
230
 
        used = 0;
231
 
 
232
 
        while (size - used >= MEM_AREA_MIN_SIZE) {
233
 
 
234
 
                i = ut_2_log(size - used);
235
 
 
236
 
                if (ut_2_exp(i) > size - used) {
237
 
 
238
 
                        /* ut_2_log rounds upward */
239
 
 
240
 
                        i--;
241
 
                }
242
 
 
243
 
                area = (mem_area_t*)(pool->buf + used);
244
 
 
245
 
                mem_area_set_size(area, ut_2_exp(i));
246
 
                mem_area_set_free(area, TRUE);
247
 
                UNIV_MEM_FREE(MEM_AREA_EXTRA_SIZE + (byte*) area,
248
 
                              ut_2_exp(i) - MEM_AREA_EXTRA_SIZE);
249
 
 
250
 
                UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
251
 
 
252
 
                used = used + ut_2_exp(i);
253
 
        }
254
 
 
255
 
        ut_ad(size >= used);
256
 
 
257
 
        pool->reserved = 0;
258
 
 
259
 
        return(pool);
260
 
}
261
 
 
262
 
/************************************************************************
263
 
Fills the specified free list. */
264
 
static
265
 
ibool
266
 
mem_pool_fill_free_list(
267
 
/*====================*/
268
 
                                /* out: TRUE if we were able to insert a
269
 
                                block to the free list */
270
 
        ulint           i,      /* in: free list index */
271
 
        mem_pool_t*     pool)   /* in: memory pool */
272
 
{
273
 
        mem_area_t*     area;
274
 
        mem_area_t*     area2;
275
 
        ibool           ret;
276
 
 
277
 
        ut_ad(mutex_own(&(pool->mutex)));
278
 
 
279
 
        if (UNIV_UNLIKELY(i >= 63)) {
280
 
                /* We come here when we have run out of space in the
281
 
                memory pool: */
282
 
 
283
 
                return(FALSE);
284
 
        }
285
 
 
286
 
        area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
287
 
 
288
 
        if (area == NULL) {
289
 
                if (UT_LIST_GET_LEN(pool->free_list[i + 1]) > 0) {
290
 
                        ut_print_timestamp(stderr);
291
 
 
292
 
                        fprintf(stderr,
293
 
                                "  InnoDB: Error: mem pool free list %lu"
294
 
                                " length is %lu\n"
295
 
                                "InnoDB: though the list is empty!\n",
296
 
                                (ulong) i + 1,
297
 
                                (ulong)
298
 
                                UT_LIST_GET_LEN(pool->free_list[i + 1]));
299
 
                }
300
 
 
301
 
                ret = mem_pool_fill_free_list(i + 1, pool);
302
 
 
303
 
                if (ret == FALSE) {
304
 
 
305
 
                        return(FALSE);
306
 
                }
307
 
 
308
 
                area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
309
 
        }
310
 
 
311
 
        if (UNIV_UNLIKELY(UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0)) {
312
 
                mem_analyze_corruption(area);
313
 
 
314
 
                ut_error;
315
 
        }
316
 
 
317
 
        UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area);
318
 
 
319
 
        area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i));
320
 
        UNIV_MEM_ALLOC(area2, MEM_AREA_EXTRA_SIZE);
321
 
 
322
 
        mem_area_set_size(area2, ut_2_exp(i));
323
 
        mem_area_set_free(area2, TRUE);
324
 
 
325
 
        UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area2);
326
 
 
327
 
        mem_area_set_size(area, ut_2_exp(i));
328
 
 
329
 
        UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
330
 
 
331
 
        return(TRUE);
332
 
}
333
 
 
334
 
/************************************************************************
335
 
Allocates memory from a pool. NOTE: This low-level function should only be
336
 
used in mem0mem.*! */
337
 
UNIV_INTERN
338
 
void*
339
 
mem_area_alloc(
340
 
/*===========*/
341
 
                                /* out, own: allocated memory buffer */
342
 
        ulint*          psize,  /* in: requested size in bytes; for optimum
343
 
                                space usage, the size should be a power of 2
344
 
                                minus MEM_AREA_EXTRA_SIZE;
345
 
                                out: allocated size in bytes (greater than
346
 
                                or equal to the requested size) */
347
 
        mem_pool_t*     pool)   /* in: memory pool */
348
 
{
349
 
        mem_area_t*     area;
350
 
        ulint           size;
351
 
        ulint           n;
352
 
        ibool           ret;
353
 
 
354
 
        /* If we are using os allocator just make a simple call
355
 
        to malloc */
356
 
        if (UNIV_LIKELY(srv_use_sys_malloc)) {
357
 
                return(malloc(*psize));
358
 
        }
359
 
 
360
 
        size = *psize;
361
 
        n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));
362
 
 
363
 
        mutex_enter(&(pool->mutex));
364
 
        mem_n_threads_inside++;
365
 
 
366
 
        ut_a(mem_n_threads_inside == 1);
367
 
 
368
 
        area = UT_LIST_GET_FIRST(pool->free_list[n]);
369
 
 
370
 
        if (area == NULL) {
371
 
                ret = mem_pool_fill_free_list(n, pool);
372
 
 
373
 
                if (ret == FALSE) {
374
 
                        /* Out of memory in memory pool: we try to allocate
375
 
                        from the operating system with the regular malloc: */
376
 
 
377
 
                        mem_n_threads_inside--;
378
 
                        mutex_exit(&(pool->mutex));
379
 
 
380
 
                        return(ut_malloc(size));
381
 
                }
382
 
 
383
 
                area = UT_LIST_GET_FIRST(pool->free_list[n]);
384
 
        }
385
 
 
386
 
        if (!mem_area_get_free(area)) {
387
 
                fprintf(stderr,
388
 
                        "InnoDB: Error: Removing element from mem pool"
389
 
                        " free list %lu though the\n"
390
 
                        "InnoDB: element is not marked free!\n",
391
 
                        (ulong) n);
392
 
 
393
 
                mem_analyze_corruption(area);
394
 
 
395
 
                /* Try to analyze a strange assertion failure reported at
396
 
                mysql@lists.mysql.com where the free bit IS 1 in the
397
 
                hex dump above */
398
 
 
399
 
                if (mem_area_get_free(area)) {
400
 
                        fprintf(stderr,
401
 
                                "InnoDB: Probably a race condition"
402
 
                                " because now the area is marked free!\n");
403
 
                }
404
 
 
405
 
                ut_error;
406
 
        }
407
 
 
408
 
        if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) {
409
 
                fprintf(stderr,
410
 
                        "InnoDB: Error: Removing element from mem pool"
411
 
                        " free list %lu\n"
412
 
                        "InnoDB: though the list length is 0!\n",
413
 
                        (ulong) n);
414
 
                mem_analyze_corruption(area);
415
 
 
416
 
                ut_error;
417
 
        }
418
 
 
419
 
        ut_ad(mem_area_get_size(area) == ut_2_exp(n));
420
 
 
421
 
        mem_area_set_free(area, FALSE);
422
 
 
423
 
        UT_LIST_REMOVE(free_list, pool->free_list[n], area);
424
 
 
425
 
        pool->reserved += mem_area_get_size(area);
426
 
 
427
 
        mem_n_threads_inside--;
428
 
        mutex_exit(&(pool->mutex));
429
 
 
430
 
        ut_ad(mem_pool_validate(pool));
431
 
 
432
 
        *psize = ut_2_exp(n) - MEM_AREA_EXTRA_SIZE;
433
 
        UNIV_MEM_ALLOC(MEM_AREA_EXTRA_SIZE + (byte*)area, *psize);
434
 
 
435
 
        return((void*)(MEM_AREA_EXTRA_SIZE + ((byte*)area)));
436
 
}
437
 
 
438
 
/************************************************************************
439
 
Gets the buddy of an area, if it exists in pool. */
440
 
UNIV_INLINE
441
 
mem_area_t*
442
 
mem_area_get_buddy(
443
 
/*===============*/
444
 
                                /* out: the buddy, NULL if no buddy in pool */
445
 
        mem_area_t*     area,   /* in: memory area */
446
 
        ulint           size,   /* in: memory area size */
447
 
        mem_pool_t*     pool)   /* in: memory pool */
448
 
{
449
 
        mem_area_t*     buddy;
450
 
 
451
 
        ut_ad(size != 0);
452
 
 
453
 
        if (((((byte*)area) - pool->buf) % (2 * size)) == 0) {
454
 
 
455
 
                /* The buddy is in a higher address */
456
 
 
457
 
                buddy = (mem_area_t*)(((byte*)area) + size);
458
 
 
459
 
                if ((((byte*)buddy) - pool->buf) + size > pool->size) {
460
 
 
461
 
                        /* The buddy is not wholly contained in the pool:
462
 
                        there is no buddy */
463
 
 
464
 
                        buddy = NULL;
465
 
                }
466
 
        } else {
467
 
                /* The buddy is in a lower address; NOTE that area cannot
468
 
                be at the pool lower end, because then we would end up to
469
 
                the upper branch in this if-clause: the remainder would be
470
 
                0 */
471
 
 
472
 
                buddy = (mem_area_t*)(((byte*)area) - size);
473
 
        }
474
 
 
475
 
        return(buddy);
476
 
}
477
 
 
478
 
/************************************************************************
479
 
Frees memory to a pool. */
480
 
UNIV_INTERN
481
 
void
482
 
mem_area_free(
483
 
/*==========*/
484
 
        void*           ptr,    /* in, own: pointer to allocated memory
485
 
                                buffer */
486
 
        mem_pool_t*     pool)   /* in: memory pool */
487
 
{
488
 
        mem_area_t*     area;
489
 
        mem_area_t*     buddy;
490
 
        void*           new_ptr;
491
 
        ulint           size;
492
 
        ulint           n;
493
 
 
494
 
        if (UNIV_LIKELY(srv_use_sys_malloc)) {
495
 
                free(ptr);
496
 
 
497
 
                return;
498
 
        }
499
 
 
500
 
        /* It may be that the area was really allocated from the OS with
501
 
        regular malloc: check if ptr points within our memory pool */
502
 
 
503
 
        if ((byte*)ptr < pool->buf || (byte*)ptr >= pool->buf + pool->size) {
504
 
                ut_free(ptr);
505
 
 
506
 
                return;
507
 
        }
508
 
 
509
 
        area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE);
510
 
 
511
 
        if (mem_area_get_free(area)) {
512
 
                fprintf(stderr,
513
 
                        "InnoDB: Error: Freeing element to mem pool"
514
 
                        " free list though the\n"
515
 
                        "InnoDB: element is marked free!\n");
516
 
 
517
 
                mem_analyze_corruption(area);
518
 
                ut_error;
519
 
        }
520
 
 
521
 
        size = mem_area_get_size(area);
522
 
        UNIV_MEM_FREE(ptr, size - MEM_AREA_EXTRA_SIZE);
523
 
 
524
 
        if (size == 0) {
525
 
                fprintf(stderr,
526
 
                        "InnoDB: Error: Mem area size is 0. Possibly a"
527
 
                        " memory overrun of the\n"
528
 
                        "InnoDB: previous allocated area!\n");
529
 
 
530
 
                mem_analyze_corruption(area);
531
 
                ut_error;
532
 
        }
533
 
 
534
 
#ifdef UNIV_LIGHT_MEM_DEBUG
535
 
        if (((byte*)area) + size < pool->buf + pool->size) {
536
 
 
537
 
                ulint   next_size;
538
 
 
539
 
                next_size = mem_area_get_size(
540
 
                        (mem_area_t*)(((byte*)area) + size));
541
 
                if (UNIV_UNLIKELY(!next_size || !ut_is_2pow(next_size))) {
542
 
                        fprintf(stderr,
543
 
                                "InnoDB: Error: Memory area size %lu,"
544
 
                                " next area size %lu not a power of 2!\n"
545
 
                                "InnoDB: Possibly a memory overrun of"
546
 
                                " the buffer being freed here.\n",
547
 
                                (ulong) size, (ulong) next_size);
548
 
                        mem_analyze_corruption(area);
549
 
 
550
 
                        ut_error;
551
 
                }
552
 
        }
553
 
#endif
554
 
        buddy = mem_area_get_buddy(area, size, pool);
555
 
 
556
 
        n = ut_2_log(size);
557
 
 
558
 
        mutex_enter(&(pool->mutex));
559
 
        mem_n_threads_inside++;
560
 
 
561
 
        ut_a(mem_n_threads_inside == 1);
562
 
 
563
 
        if (buddy && mem_area_get_free(buddy)
564
 
            && (size == mem_area_get_size(buddy))) {
565
 
 
566
 
                /* The buddy is in a free list */
567
 
 
568
 
                if ((byte*)buddy < (byte*)area) {
569
 
                        new_ptr = ((byte*)buddy) + MEM_AREA_EXTRA_SIZE;
570
 
 
571
 
                        mem_area_set_size(buddy, 2 * size);
572
 
                        mem_area_set_free(buddy, FALSE);
573
 
                } else {
574
 
                        new_ptr = ptr;
575
 
 
576
 
                        mem_area_set_size(area, 2 * size);
577
 
                }
578
 
 
579
 
                /* Remove the buddy from its free list and merge it to area */
580
 
 
581
 
                UT_LIST_REMOVE(free_list, pool->free_list[n], buddy);
582
 
 
583
 
                pool->reserved += ut_2_exp(n);
584
 
 
585
 
                mem_n_threads_inside--;
586
 
                mutex_exit(&(pool->mutex));
587
 
 
588
 
                mem_area_free(new_ptr, pool);
589
 
 
590
 
                return;
591
 
        } else {
592
 
                UT_LIST_ADD_FIRST(free_list, pool->free_list[n], area);
593
 
 
594
 
                mem_area_set_free(area, TRUE);
595
 
 
596
 
                ut_ad(pool->reserved >= size);
597
 
 
598
 
                pool->reserved -= size;
599
 
        }
600
 
 
601
 
        mem_n_threads_inside--;
602
 
        mutex_exit(&(pool->mutex));
603
 
 
604
 
        ut_ad(mem_pool_validate(pool));
605
 
}
606
 
 
607
 
/************************************************************************
608
 
Validates a memory pool. */
609
 
UNIV_INTERN
610
 
ibool
611
 
mem_pool_validate(
612
 
/*==============*/
613
 
                                /* out: TRUE if ok */
614
 
        mem_pool_t*     pool)   /* in: memory pool */
615
 
{
616
 
        mem_area_t*     area;
617
 
        mem_area_t*     buddy;
618
 
        ulint           free;
619
 
        ulint           i;
620
 
 
621
 
        mutex_enter(&(pool->mutex));
622
 
 
623
 
        free = 0;
624
 
 
625
 
        for (i = 0; i < 64; i++) {
626
 
 
627
 
                UT_LIST_VALIDATE(free_list, mem_area_t, pool->free_list[i]);
628
 
 
629
 
                area = UT_LIST_GET_FIRST(pool->free_list[i]);
630
 
 
631
 
                while (area != NULL) {
632
 
                        ut_a(mem_area_get_free(area));
633
 
                        ut_a(mem_area_get_size(area) == ut_2_exp(i));
634
 
 
635
 
                        buddy = mem_area_get_buddy(area, ut_2_exp(i), pool);
636
 
 
637
 
                        ut_a(!buddy || !mem_area_get_free(buddy)
638
 
                             || (ut_2_exp(i) != mem_area_get_size(buddy)));
639
 
 
640
 
                        area = UT_LIST_GET_NEXT(free_list, area);
641
 
 
642
 
                        free += ut_2_exp(i);
643
 
                }
644
 
        }
645
 
 
646
 
        ut_a(free + pool->reserved == pool->size);
647
 
 
648
 
        mutex_exit(&(pool->mutex));
649
 
 
650
 
        return(TRUE);
651
 
}
652
 
 
653
 
/************************************************************************
654
 
Prints info of a memory pool. */
655
 
UNIV_INTERN
656
 
void
657
 
mem_pool_print_info(
658
 
/*================*/
659
 
        FILE*           outfile,/* in: output file to write to */
660
 
        mem_pool_t*     pool)   /* in: memory pool */
661
 
{
662
 
        ulint           i;
663
 
 
664
 
        mem_pool_validate(pool);
665
 
 
666
 
        fprintf(outfile, "INFO OF A MEMORY POOL\n");
667
 
 
668
 
        mutex_enter(&(pool->mutex));
669
 
 
670
 
        for (i = 0; i < 64; i++) {
671
 
                if (UT_LIST_GET_LEN(pool->free_list[i]) > 0) {
672
 
 
673
 
                        fprintf(outfile,
674
 
                                "Free list length %lu for"
675
 
                                " blocks of size %lu\n",
676
 
                                (ulong) UT_LIST_GET_LEN(pool->free_list[i]),
677
 
                                (ulong) ut_2_exp(i));
678
 
                }
679
 
        }
680
 
 
681
 
        fprintf(outfile, "Pool size %lu, reserved %lu.\n", (ulong) pool->size,
682
 
                (ulong) pool->reserved);
683
 
        mutex_exit(&(pool->mutex));
684
 
}
685
 
 
686
 
/************************************************************************
687
 
Returns the amount of reserved memory. */
688
 
UNIV_INTERN
689
 
ulint
690
 
mem_pool_get_reserved(
691
 
/*==================*/
692
 
                                /* out: reserved memory in bytes */
693
 
        mem_pool_t*     pool)   /* in: memory pool */
694
 
{
695
 
        ulint   reserved;
696
 
 
697
 
        mutex_enter(&(pool->mutex));
698
 
 
699
 
        reserved = pool->reserved;
700
 
 
701
 
        mutex_exit(&(pool->mutex));
702
 
 
703
 
        return(reserved);
704
 
}