~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to innobase/mem/mem0pool.c

  • Committer: monty at mysql
  • Date: 2001-02-17 12:19:19 UTC
  • mto: (554.1.1)
  • mto: This revision was merged to the branch mainline in revision 556.
  • Revision ID: sp1r-monty@donna.mysql.com-20010217121919-07904
Added Innobase to source distribution

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************
 
2
The lowest-level memory management
 
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
 
6
Created 5/12/1997 Heikki Tuuri
 
7
*************************************************************************/
 
8
 
 
9
#include "mem0pool.h"
 
10
#ifdef UNIV_NONINL
 
11
#include "mem0pool.ic"
 
12
#endif
 
13
 
 
14
#include "sync0sync.h"
 
15
#include "ut0mem.h"
 
16
#include "ut0lst.h"
 
17
#include "ut0byte.h"
 
18
 
 
19
/* We would like to use also the buffer frames to allocate memory. This
 
20
would be desirable, because then the memory consumption of the database
 
21
would be fixed, and we might even lock the buffer pool to the main memory.
 
22
The problem here is that the buffer management routines can themselves call
 
23
memory allocation, while the buffer pool mutex is reserved.
 
24
 
 
25
The main components of the memory consumption are:
 
26
 
 
27
1. buffer pool,
 
28
2. parsed and optimized SQL statements,
 
29
3. data dictionary cache,
 
30
4. log buffer,
 
31
5. locks for each transaction,
 
32
6. hash table for the adaptive index,
 
33
7. state and buffers for each SQL query currently being executed,
 
34
8. session for each user, and
 
35
9. stack for each OS thread.
 
36
 
 
37
Items 1-3 are managed by an LRU algorithm. Items 5 and 6 can potentially
 
38
consume very much memory. Items 7 and 8 should consume quite little memory,
 
39
and the OS should take care of item 9, which too should consume little memory.
 
40
 
 
41
A solution to the memory management:
 
42
 
 
43
1. the buffer pool size is set separately;
 
44
2. log buffer size is set separately;
 
45
3. the common pool size for all the other entries, except 8, is set separately.
 
46
 
 
47
Problems: we may waste memory if the common pool is set too big. Another
 
48
problem is the locks, which may take very much space in big transactions.
 
49
Then the shared pool size should be set very big. We can allow locks to take
 
50
space from the buffer pool, but the SQL optimizer is then unaware of the
 
51
usable size of the buffer pool. We could also combine the objects in the
 
52
common pool and the buffers in the buffer pool into a single LRU list and
 
53
manage it uniformly, but this approach does not take into account the parsing
 
54
and other costs unique to SQL statements.
 
55
 
 
56
So, let the SQL statements and the data dictionary entries form one single
 
57
LRU list, let us call it the dictionary LRU list. The locks for a transaction
 
58
can be seen as a part of the state of the transaction. Hence, they should be
 
59
stored in the common pool. We still have the problem of a very big update
 
60
transaction, for example, which will set very many x-locks on rows, and the
 
61
locks will consume a lot of memory, say, half of the buffer pool size.
 
62
 
 
63
Another problem is what to do if we are not able to malloc a requested
 
64
block of memory from the common pool. Then we can truncate the LRU list of
 
65
the dictionary cache. If it does not help, a system error results.
 
66
 
 
67
Because 5 and 6 may potentially consume very much memory, we let them grow
 
68
into the buffer pool. We may let the locks of a transaction take frames
 
69
from the buffer pool, when the corresponding memory heap block has grown to
 
70
the size of a buffer frame. Similarly for the hash node cells of the locks,
 
71
and for the adaptive index. Thus, for each individual transaction, its locks
 
72
can occupy at most about the size of the buffer frame of memory in the common
 
73
pool, and after that its locks will grow into the buffer pool. */
 
74
 
 
75
/* Memory area header */
 
76
 
 
77
struct mem_area_struct{
 
78
        ulint           size_and_free;  /* memory area size is obtained by
 
79
                                        anding with ~MEM_AREA_FREE; area in
 
80
                                        a free list if ANDing with
 
81
                                        MEM_AREA_FREE results in nonzero */ 
 
82
        UT_LIST_NODE_T(mem_area_t)
 
83
                        free_list;      /* free list node */
 
84
};
 
85
 
 
86
/* Mask used to extract the free bit from area->size */
 
87
#define MEM_AREA_FREE   1
 
88
 
 
89
/* The smallest memory area total size */
 
90
#define MEM_AREA_MIN_SIZE       (2 * UNIV_MEM_ALIGNMENT)
 
91
 
 
92
/* Data structure for a memory pool. The space is allocated using the buddy
 
93
algorithm, where free list i contains areas of size 2 to power i. */
 
94
 
 
95
struct mem_pool_struct{
 
96
        byte*           buf;            /* memory pool */
 
97
        ulint           size;           /* memory common pool size */
 
98
        ulint           reserved;       /* amount of currently allocated
 
99
                                        memory */
 
100
        mutex_t         mutex;          /* mutex protecting this struct */
 
101
        UT_LIST_BASE_NODE_T(mem_area_t)
 
102
                        free_list[64];  /* lists of free memory areas: an
 
103
                                        area is put to the list whose number
 
104
                                        is the 2-logarithm of the area size */
 
105
};
 
106
 
 
107
/* The common memory pool */
 
108
mem_pool_t*     mem_comm_pool   = NULL;
 
109
 
 
110
ulint           mem_out_of_mem_err_msg_count    = 0;
 
111
 
 
112
/************************************************************************
 
113
Returns memory area size. */
 
114
UNIV_INLINE
 
115
ulint
 
116
mem_area_get_size(
 
117
/*==============*/
 
118
                                /* out: size */
 
119
        mem_area_t*     area)   /* in: area */
 
120
{
 
121
        return(area->size_and_free & ~MEM_AREA_FREE);
 
122
}
 
123
 
 
124
/************************************************************************
 
125
Sets memory area size. */
 
126
UNIV_INLINE
 
127
void
 
128
mem_area_set_size(
 
129
/*==============*/
 
130
        mem_area_t*     area,   /* in: area */
 
131
        ulint           size)   /* in: size */
 
132
{
 
133
        area->size_and_free = (area->size_and_free & MEM_AREA_FREE)
 
134
                                | size;
 
135
}
 
136
 
 
137
/************************************************************************
 
138
Returns memory area free bit. */
 
139
UNIV_INLINE
 
140
ibool
 
141
mem_area_get_free(
 
142
/*==============*/
 
143
                                /* out: TRUE if free */
 
144
        mem_area_t*     area)   /* in: area */
 
145
{
 
146
        ut_ad(TRUE == MEM_AREA_FREE);
 
147
 
 
148
        return(area->size_and_free & MEM_AREA_FREE);
 
149
}
 
150
 
 
151
/************************************************************************
 
152
Sets memory area free bit. */
 
153
UNIV_INLINE
 
154
void
 
155
mem_area_set_free(
 
156
/*==============*/
 
157
        mem_area_t*     area,   /* in: area */
 
158
        ibool           free)   /* in: free bit value */
 
159
{
 
160
        ut_ad(TRUE == MEM_AREA_FREE);
 
161
        
 
162
        area->size_and_free = (area->size_and_free & ~MEM_AREA_FREE)
 
163
                                | free;
 
164
}
 
165
 
 
166
/************************************************************************
 
167
Creates a memory pool. */
 
168
 
 
169
mem_pool_t*
 
170
mem_pool_create(
 
171
/*============*/
 
172
                        /* out: memory pool */
 
173
        ulint   size)   /* in: pool size in bytes */
 
174
{
 
175
        mem_pool_t*     pool;
 
176
        mem_area_t*     area;
 
177
        ulint           i;
 
178
        ulint           used;
 
179
 
 
180
        ut_a(size > 10000);
 
181
        
 
182
        pool = ut_malloc(sizeof(mem_pool_t));
 
183
 
 
184
        pool->buf = ut_malloc(size);
 
185
        pool->size = size;
 
186
 
 
187
        mutex_create(&(pool->mutex));
 
188
        mutex_set_level(&(pool->mutex), SYNC_MEM_POOL);
 
189
 
 
190
        /* Initialize the free lists */
 
191
 
 
192
        for (i = 0; i < 64; i++) {
 
193
 
 
194
                UT_LIST_INIT(pool->free_list[i]);
 
195
        }
 
196
 
 
197
        used = 0;
 
198
 
 
199
        while (size - used >= MEM_AREA_MIN_SIZE) {
 
200
 
 
201
                i = ut_2_log(size - used);
 
202
 
 
203
                if (ut_2_exp(i) > size - used) {
 
204
 
 
205
                        /* ut_2_log rounds upward */
 
206
                
 
207
                        i--;
 
208
                }
 
209
 
 
210
                area = (mem_area_t*)(pool->buf + used);
 
211
 
 
212
                mem_area_set_size(area, ut_2_exp(i));
 
213
                mem_area_set_free(area, TRUE);
 
214
 
 
215
                UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
 
216
 
 
217
                used = used + ut_2_exp(i);
 
218
        }
 
219
 
 
220
        ut_ad(size >= used);
 
221
 
 
222
        pool->reserved = 0;
 
223
        
 
224
        return(pool);
 
225
}
 
226
 
 
227
/************************************************************************
 
228
Fills the specified free list. */
 
229
static
 
230
ibool
 
231
mem_pool_fill_free_list(
 
232
/*====================*/
 
233
                                /* out: TRUE if we were able to insert a
 
234
                                block to the free list */
 
235
        ulint           i,      /* in: free list index */
 
236
        mem_pool_t*     pool)   /* in: memory pool */
 
237
{
 
238
        mem_area_t*     area;
 
239
        mem_area_t*     area2;
 
240
        ibool           ret;
 
241
 
 
242
        ut_ad(mutex_own(&(pool->mutex)));
 
243
 
 
244
        if (i >= 63) {
 
245
                /* We come here when we have run out of space in the
 
246
                memory pool: */
 
247
 
 
248
                if (mem_out_of_mem_err_msg_count % 1000 == 0) {
 
249
                        /* We do not print the message every time: */
 
250
                        
 
251
                        fprintf(stderr,
 
252
        "Innobase: Warning: out of memory in additional memory pool.\n");
 
253
                        fprintf(stderr,
 
254
        "Innobase: Innobase will start allocating memory from the OS.\n");
 
255
                        fprintf(stderr,
 
256
        "Innobase: You should restart the database with a bigger value in\n");
 
257
                        fprintf(stderr,
 
258
     "Innobase: the MySQL .cnf file for innobase_additional_mem_pool_size.\n");
 
259
                }
 
260
 
 
261
                mem_out_of_mem_err_msg_count++;
 
262
     
 
263
                return(FALSE);
 
264
        }
 
265
 
 
266
        area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
 
267
 
 
268
        if (area == NULL) {
 
269
                ret = mem_pool_fill_free_list(i + 1, pool);
 
270
 
 
271
                if (ret == FALSE) {
 
272
                        return(FALSE);
 
273
                }
 
274
 
 
275
                area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
 
276
        }
 
277
        
 
278
        UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area);
 
279
 
 
280
        area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i));
 
281
 
 
282
        mem_area_set_size(area2, ut_2_exp(i));
 
283
        mem_area_set_free(area2, TRUE);
 
284
 
 
285
        UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area2);
 
286
        
 
287
        mem_area_set_size(area, ut_2_exp(i));
 
288
 
 
289
        UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
 
290
 
 
291
        return(TRUE);
 
292
}
 
293
        
 
294
/************************************************************************
 
295
Allocates memory from a pool. NOTE: This low-level function should only be
 
296
used in mem0mem.*! */
 
297
 
 
298
void*
 
299
mem_area_alloc(
 
300
/*===========*/
 
301
                                /* out, own: allocated memory buffer */
 
302
        ulint           size,   /* in: allocated size in bytes; for optimum
 
303
                                space usage, the size should be a power of 2
 
304
                                minus MEM_AREA_EXTRA_SIZE */
 
305
        mem_pool_t*     pool)   /* in: memory pool */
 
306
{
 
307
        mem_area_t*     area;
 
308
        ulint           n;
 
309
        ibool           ret;
 
310
 
 
311
        n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));
 
312
 
 
313
        mutex_enter(&(pool->mutex));
 
314
 
 
315
        area = UT_LIST_GET_FIRST(pool->free_list[n]);
 
316
 
 
317
        if (area == NULL) {
 
318
                ret = mem_pool_fill_free_list(n, pool);
 
319
 
 
320
                if (ret == FALSE) {
 
321
                        /* Out of memory in memory pool: we try to allocate
 
322
                        from the operating system with the regular malloc: */
 
323
 
 
324
                        mutex_exit(&(pool->mutex));
 
325
 
 
326
                        return(ut_malloc(size));
 
327
                }
 
328
 
 
329
                area = UT_LIST_GET_FIRST(pool->free_list[n]);
 
330
        }
 
331
 
 
332
        ut_a(mem_area_get_free(area));
 
333
        ut_ad(mem_area_get_size(area) == ut_2_exp(n));  
 
334
 
 
335
        mem_area_set_free(area, FALSE);
 
336
        
 
337
        UT_LIST_REMOVE(free_list, pool->free_list[n], area);
 
338
 
 
339
        pool->reserved += mem_area_get_size(area);
 
340
        
 
341
        mutex_exit(&(pool->mutex));
 
342
 
 
343
        ut_ad(mem_pool_validate(pool));
 
344
        
 
345
        return((void*)(MEM_AREA_EXTRA_SIZE + ((byte*)area))); 
 
346
}
 
347
 
 
348
/************************************************************************
 
349
Gets the buddy of an area, if it exists in pool. */
 
350
UNIV_INLINE
 
351
mem_area_t*
 
352
mem_area_get_buddy(
 
353
/*===============*/
 
354
                                /* out: the buddy, NULL if no buddy in pool */
 
355
        mem_area_t*     area,   /* in: memory area */
 
356
        ulint           size,   /* in: memory area size */
 
357
        mem_pool_t*     pool)   /* in: memory pool */
 
358
{
 
359
        mem_area_t*     buddy;
 
360
 
 
361
        ut_ad(size != 0);
 
362
 
 
363
        if (((((byte*)area) - pool->buf) % (2 * size)) == 0) {
 
364
        
 
365
                /* The buddy is in a higher address */
 
366
 
 
367
                buddy = (mem_area_t*)(((byte*)area) + size);
 
368
 
 
369
                if ((((byte*)buddy) - pool->buf) + size > pool->size) {
 
370
 
 
371
                        /* The buddy is not wholly contained in the pool:
 
372
                        there is no buddy */
 
373
 
 
374
                        buddy = NULL;
 
375
                }
 
376
        } else {
 
377
                /* The buddy is in a lower address; NOTE that area cannot
 
378
                be at the pool lower end, because then we would end up to
 
379
                the upper branch in this if-clause: the remainder would be
 
380
                0 */
 
381
 
 
382
                buddy = (mem_area_t*)(((byte*)area) - size);
 
383
        }
 
384
 
 
385
        return(buddy);
 
386
}
 
387
 
 
388
/************************************************************************
 
389
Frees memory to a pool. */
 
390
 
 
391
void
 
392
mem_area_free(
 
393
/*==========*/
 
394
        void*           ptr,    /* in, own: pointer to allocated memory
 
395
                                buffer */
 
396
        mem_pool_t*     pool)   /* in: memory pool */
 
397
{
 
398
        mem_area_t*     area;
 
399
        mem_area_t*     buddy;
 
400
        void*           new_ptr;
 
401
        ulint           size;
 
402
        ulint           n;
 
403
        
 
404
        if (mem_out_of_mem_err_msg_count > 0) {
 
405
                /* It may be that the area was really allocated from the
 
406
                OS with regular malloc: check if ptr points within
 
407
                our memory pool */
 
408
 
 
409
                if ((byte*)ptr < pool->buf
 
410
                                || (byte*)ptr >= pool->buf + pool->size) {
 
411
                        ut_free(ptr);
 
412
 
 
413
                        return;
 
414
                }
 
415
        }
 
416
 
 
417
        area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE);
 
418
 
 
419
        size = mem_area_get_size(area);
 
420
        
 
421
        ut_ad(size != 0);
 
422
        ut_a(!mem_area_get_free(area));
 
423
 
 
424
#ifdef UNIV_LIGHT_MEM_DEBUG     
 
425
        if (((byte*)area) + size < pool->buf + pool->size) {
 
426
 
 
427
                ulint   next_size;
 
428
 
 
429
                next_size = mem_area_get_size(
 
430
                                        (mem_area_t*)(((byte*)area) + size));
 
431
                ut_a(ut_2_power_up(next_size) == next_size);
 
432
        }
 
433
#endif
 
434
        buddy = mem_area_get_buddy(area, size, pool);
 
435
        
 
436
        n = ut_2_log(size);
 
437
        
 
438
        mutex_enter(&(pool->mutex));
 
439
 
 
440
        if (buddy && mem_area_get_free(buddy)
 
441
                                && (size == mem_area_get_size(buddy))) {
 
442
 
 
443
                /* The buddy is in a free list */
 
444
 
 
445
                if ((byte*)buddy < (byte*)area) {
 
446
                        new_ptr = ((byte*)buddy) + MEM_AREA_EXTRA_SIZE;
 
447
 
 
448
                        mem_area_set_size(buddy, 2 * size);
 
449
                        mem_area_set_free(buddy, FALSE);
 
450
                } else {
 
451
                        new_ptr = ptr;
 
452
 
 
453
                        mem_area_set_size(area, 2 * size);
 
454
                }
 
455
 
 
456
                /* Remove the buddy from its free list and merge it to area */
 
457
                
 
458
                UT_LIST_REMOVE(free_list, pool->free_list[n], buddy);
 
459
 
 
460
                pool->reserved += ut_2_exp(n);
 
461
 
 
462
                mutex_exit(&(pool->mutex));
 
463
 
 
464
                mem_area_free(new_ptr, pool);
 
465
 
 
466
                return;
 
467
        } else {
 
468
                UT_LIST_ADD_FIRST(free_list, pool->free_list[n], area);
 
469
 
 
470
                mem_area_set_free(area, TRUE);
 
471
 
 
472
                ut_ad(pool->reserved >= size);
 
473
 
 
474
                pool->reserved -= size;
 
475
        }
 
476
        
 
477
        mutex_exit(&(pool->mutex));
 
478
 
 
479
        ut_ad(mem_pool_validate(pool));
 
480
}
 
481
 
 
482
/************************************************************************
 
483
Validates a memory pool. */
 
484
 
 
485
ibool
 
486
mem_pool_validate(
 
487
/*==============*/
 
488
                                /* out: TRUE if ok */
 
489
        mem_pool_t*     pool)   /* in: memory pool */
 
490
{
 
491
        mem_area_t*     area;
 
492
        mem_area_t*     buddy;
 
493
        ulint           free;
 
494
        ulint           i;
 
495
 
 
496
        mutex_enter(&(pool->mutex));
 
497
 
 
498
        free = 0;
 
499
        
 
500
        for (i = 0; i < 64; i++) {
 
501
        
 
502
                UT_LIST_VALIDATE(free_list, mem_area_t, pool->free_list[i]);
 
503
 
 
504
                area = UT_LIST_GET_FIRST(pool->free_list[i]);
 
505
 
 
506
                while (area != NULL) {
 
507
                        ut_a(mem_area_get_free(area));
 
508
                        ut_a(mem_area_get_size(area) == ut_2_exp(i));
 
509
 
 
510
                        buddy = mem_area_get_buddy(area, ut_2_exp(i), pool);
 
511
 
 
512
                        ut_a(!buddy || !mem_area_get_free(buddy)
 
513
                             || (ut_2_exp(i) != mem_area_get_size(buddy)));
 
514
 
 
515
                        area = UT_LIST_GET_NEXT(free_list, area);
 
516
 
 
517
                        free += ut_2_exp(i);
 
518
                }
 
519
        }
 
520
 
 
521
        ut_a(free + pool->reserved == pool->size
 
522
                                        - (pool->size % MEM_AREA_MIN_SIZE));
 
523
        mutex_exit(&(pool->mutex));
 
524
 
 
525
        return(TRUE);
 
526
}
 
527
 
 
528
/************************************************************************
 
529
Prints info of a memory pool. */
 
530
 
 
531
void
 
532
mem_pool_print_info(
 
533
/*================*/
 
534
        FILE*           outfile,/* in: output file to write to */
 
535
        mem_pool_t*     pool)   /* in: memory pool */
 
536
{
 
537
        ulint           i;
 
538
 
 
539
        mem_pool_validate(pool);
 
540
 
 
541
        fprintf(outfile, "INFO OF A MEMORY POOL\n");
 
542
 
 
543
        mutex_enter(&(pool->mutex));
 
544
 
 
545
        for (i = 0; i < 64; i++) {
 
546
                if (UT_LIST_GET_LEN(pool->free_list[i]) > 0) {
 
547
 
 
548
                        fprintf(outfile,
 
549
                          "Free list length %lu for blocks of size %lu\n",
 
550
                          UT_LIST_GET_LEN(pool->free_list[i]),
 
551
                          ut_2_exp(i));
 
552
                }       
 
553
        }
 
554
 
 
555
        fprintf(outfile, "Pool size %lu, reserved %lu.\n", pool->size,
 
556
                                                        pool->reserved);
 
557
        mutex_exit(&(pool->mutex));
 
558
}
 
559
 
 
560
/************************************************************************
 
561
Returns the amount of reserved memory. */
 
562
 
 
563
ulint
 
564
mem_pool_get_reserved(
 
565
/*==================*/
 
566
                                /* out: reserved mmeory in bytes */
 
567
        mem_pool_t*     pool)   /* in: memory pool */
 
568
{
 
569
        ulint   reserved;
 
570
 
 
571
        mutex_enter(&(pool->mutex));
 
572
 
 
573
        reserved = pool->reserved;
 
574
        
 
575
        mutex_exit(&(pool->mutex));
 
576
 
 
577
        return(reserved);
 
578
}