~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/buf/buf0buddy.c

Fixed the clock_gettime test.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************
2
 
Binary buddy allocator for compressed pages
3
 
 
4
 
(c) 2006 Innobase Oy
5
 
 
6
 
Created December 2006 by Marko Makela
7
 
*******************************************************/
8
 
 
9
 
#define THIS_MODULE
10
 
#include "buf0buddy.h"
11
 
#ifdef UNIV_NONINL
12
 
# include "buf0buddy.ic"
13
 
#endif
14
 
#undef THIS_MODULE
15
 
#include "buf0buf.h"
16
 
#include "buf0lru.h"
17
 
#include "buf0flu.h"
18
 
#include "page0zip.h"
19
 
 
20
 
/* Statistic counters */
21
 
 
22
 
#ifdef UNIV_DEBUG
23
 
/** Number of frames allocated from the buffer pool to the buddy system.
24
 
Protected by buf_pool_mutex. */
25
 
static ulint buf_buddy_n_frames;
26
 
#endif /* UNIV_DEBUG */
27
 
/** Statistics of the buddy system, indexed by block size.
28
 
Protected by buf_pool_mutex. */
29
 
UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1];
30
 
 
31
 
/**************************************************************************
32
 
Get the offset of the buddy of a compressed page frame. */
33
 
UNIV_INLINE
34
 
byte*
35
 
buf_buddy_get(
36
 
/*==========*/
37
 
                        /* out: the buddy relative of page */
38
 
        byte*   page,   /* in: compressed page */
39
 
        ulint   size)   /* in: page size in bytes */
40
 
{
41
 
        ut_ad(ut_is_2pow(size));
42
 
        ut_ad(size >= BUF_BUDDY_LOW);
43
 
        ut_ad(size < BUF_BUDDY_HIGH);
44
 
        ut_ad(!ut_align_offset(page, size));
45
 
 
46
 
        if (((ulint) page) & size) {
47
 
                return(page - size);
48
 
        } else {
49
 
                return(page + size);
50
 
        }
51
 
}
52
 
 
53
 
/**************************************************************************
54
 
Add a block to the head of the appropriate buddy free list. */
55
 
UNIV_INLINE
56
 
void
57
 
buf_buddy_add_to_free(
58
 
/*==================*/
59
 
        buf_page_t*     bpage,  /* in,own: block to be freed */
60
 
        ulint           i)      /* in: index of buf_pool->zip_free[] */
61
 
{
62
 
#ifdef UNIV_DEBUG_VALGRIND
63
 
        buf_page_t*     b  = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
64
 
 
65
 
        if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i);
66
 
#endif /* UNIV_DEBUG_VALGRIND */
67
 
 
68
 
        ut_ad(buf_pool->zip_free[i].start != bpage);
69
 
        UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
70
 
 
71
 
#ifdef UNIV_DEBUG_VALGRIND
72
 
        if (b) UNIV_MEM_FREE(b, BUF_BUDDY_LOW << i);
73
 
        UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
74
 
#endif /* UNIV_DEBUG_VALGRIND */
75
 
}
76
 
 
77
 
/**************************************************************************
78
 
Remove a block from the appropriate buddy free list. */
79
 
UNIV_INLINE
80
 
void
81
 
buf_buddy_remove_from_free(
82
 
/*=======================*/
83
 
        buf_page_t*     bpage,  /* in: block to be removed */
84
 
        ulint           i)      /* in: index of buf_pool->zip_free[] */
85
 
{
86
 
#ifdef UNIV_DEBUG_VALGRIND
87
 
        buf_page_t*     prev = UT_LIST_GET_PREV(list, bpage);
88
 
        buf_page_t*     next = UT_LIST_GET_NEXT(list, bpage);
89
 
 
90
 
        if (prev) UNIV_MEM_VALID(prev, BUF_BUDDY_LOW << i);
91
 
        if (next) UNIV_MEM_VALID(next, BUF_BUDDY_LOW << i);
92
 
 
93
 
        ut_ad(!prev || buf_page_get_state(prev) == BUF_BLOCK_ZIP_FREE);
94
 
        ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
95
 
#endif /* UNIV_DEBUG_VALGRIND */
96
 
 
97
 
        ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
98
 
        UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
99
 
 
100
 
#ifdef UNIV_DEBUG_VALGRIND
101
 
        if (prev) UNIV_MEM_FREE(prev, BUF_BUDDY_LOW << i);
102
 
        if (next) UNIV_MEM_FREE(next, BUF_BUDDY_LOW << i);
103
 
#endif /* UNIV_DEBUG_VALGRIND */
104
 
}
105
 
 
106
 
/**************************************************************************
107
 
Try to allocate a block from buf_pool->zip_free[]. */
108
 
static
109
 
void*
110
 
buf_buddy_alloc_zip(
111
 
/*================*/
112
 
                        /* out: allocated block, or NULL
113
 
                        if buf_pool->zip_free[] was empty */
114
 
        ulint   i)      /* in: index of buf_pool->zip_free[] */
115
 
{
116
 
        buf_page_t*     bpage;
117
 
 
118
 
        ut_ad(buf_pool_mutex_own());
119
 
        ut_a(i < BUF_BUDDY_SIZES);
120
 
 
121
 
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
122
 
        /* Valgrind would complain about accessing free memory. */
123
 
        UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]);
124
 
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
125
 
        bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
126
 
 
127
 
        if (bpage) {
128
 
                UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
129
 
                ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
130
 
 
131
 
                buf_buddy_remove_from_free(bpage, i);
132
 
        } else if (i + 1 < BUF_BUDDY_SIZES) {
133
 
                /* Attempt to split. */
134
 
                bpage = buf_buddy_alloc_zip(i + 1);
135
 
 
136
 
                if (bpage) {
137
 
                        buf_page_t*     buddy = (buf_page_t*)
138
 
                                (((char*) bpage) + (BUF_BUDDY_LOW << i));
139
 
 
140
 
                        ut_ad(!buf_pool_contains_zip(buddy));
141
 
                        ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
142
 
                        buddy->state = BUF_BLOCK_ZIP_FREE;
143
 
                        buf_buddy_add_to_free(buddy, i);
144
 
                }
145
 
        }
146
 
 
147
 
#ifdef UNIV_DEBUG
148
 
        if (bpage) {
149
 
                memset(bpage, ~i, BUF_BUDDY_LOW << i);
150
 
        }
151
 
#endif /* UNIV_DEBUG */
152
 
 
153
 
        UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i);
154
 
 
155
 
        return(bpage);
156
 
}
157
 
 
158
 
/**************************************************************************
159
 
Deallocate a buffer frame of UNIV_PAGE_SIZE. */
160
 
static
161
 
void
162
 
buf_buddy_block_free(
163
 
/*=================*/
164
 
        void*   buf)    /* in: buffer frame to deallocate */
165
 
{
166
 
        const ulint     fold    = BUF_POOL_ZIP_FOLD_PTR(buf);
167
 
        buf_page_t*     bpage;
168
 
        buf_block_t*    block;
169
 
 
170
 
        ut_ad(buf_pool_mutex_own());
171
 
        ut_ad(!mutex_own(&buf_pool_zip_mutex));
172
 
        ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE));
173
 
 
174
 
        HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage,
175
 
                    ((buf_block_t*) bpage)->frame == buf);
176
 
        ut_a(bpage);
177
 
        ut_a(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY);
178
 
        ut_ad(!bpage->in_page_hash);
179
 
        ut_ad(bpage->in_zip_hash);
180
 
        ut_d(bpage->in_zip_hash = FALSE);
181
 
        HASH_DELETE(buf_page_t, hash, buf_pool->zip_hash, fold, bpage);
182
 
 
183
 
        ut_d(memset(buf, 0, UNIV_PAGE_SIZE));
184
 
        UNIV_MEM_INVALID(buf, UNIV_PAGE_SIZE);
185
 
 
186
 
        block = (buf_block_t*) bpage;
187
 
        mutex_enter(&block->mutex);
188
 
        buf_LRU_block_free_non_file_page(block);
189
 
        mutex_exit(&block->mutex);
190
 
 
191
 
        ut_ad(buf_buddy_n_frames > 0);
192
 
        ut_d(buf_buddy_n_frames--);
193
 
}
194
 
 
195
 
/**************************************************************************
196
 
Allocate a buffer block to the buddy allocator. */
197
 
static
198
 
void
199
 
buf_buddy_block_register(
200
 
/*=====================*/
201
 
        buf_block_t*    block)  /* in: buffer frame to allocate */
202
 
{
203
 
        const ulint     fold = BUF_POOL_ZIP_FOLD(block);
204
 
        ut_ad(buf_pool_mutex_own());
205
 
        ut_ad(!mutex_own(&buf_pool_zip_mutex));
206
 
 
207
 
        buf_block_set_state(block, BUF_BLOCK_MEMORY);
208
 
 
209
 
        ut_a(block->frame);
210
 
        ut_a(!ut_align_offset(block->frame, UNIV_PAGE_SIZE));
211
 
 
212
 
        ut_ad(!block->page.in_page_hash);
213
 
        ut_ad(!block->page.in_zip_hash);
214
 
        ut_d(block->page.in_zip_hash = TRUE);
215
 
        HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
216
 
 
217
 
        ut_d(buf_buddy_n_frames++);
218
 
}
219
 
 
220
 
/**************************************************************************
221
 
Allocate a block from a bigger object. */
222
 
static
223
 
void*
224
 
buf_buddy_alloc_from(
225
 
/*=================*/
226
 
                                /* out: allocated block */
227
 
        void*           buf,    /* in: a block that is free to use */
228
 
        ulint           i,      /* in: index of buf_pool->zip_free[] */
229
 
        ulint           j)      /* in: size of buf as an index
230
 
                                of buf_pool->zip_free[] */
231
 
{
232
 
        ulint   offs    = BUF_BUDDY_LOW << j;
233
 
        ut_ad(j <= BUF_BUDDY_SIZES);
234
 
        ut_ad(j >= i);
235
 
        ut_ad(!ut_align_offset(buf, offs));
236
 
 
237
 
        /* Add the unused parts of the block to the free lists. */
238
 
        while (j > i) {
239
 
                buf_page_t*     bpage;
240
 
 
241
 
                offs >>= 1;
242
 
                j--;
243
 
 
244
 
                bpage = (buf_page_t*) ((byte*) buf + offs);
245
 
                ut_d(memset(bpage, j, BUF_BUDDY_LOW << j));
246
 
                bpage->state = BUF_BLOCK_ZIP_FREE;
247
 
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
248
 
                /* Valgrind would complain about accessing free memory. */
249
 
                UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[j]);
250
 
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
251
 
                buf_buddy_add_to_free(bpage, j);
252
 
        }
253
 
 
254
 
        return(buf);
255
 
}
256
 
 
257
 
/**************************************************************************
258
 
Allocate a block.  The thread calling this function must hold
259
 
buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex.
260
 
The buf_pool_mutex may only be released and reacquired if lru != NULL. */
261
 
UNIV_INTERN
262
 
void*
263
 
buf_buddy_alloc_low(
264
 
/*================*/
265
 
                        /* out: allocated block,
266
 
                        possibly NULL if lru==NULL */
267
 
        ulint   i,      /* in: index of buf_pool->zip_free[],
268
 
                        or BUF_BUDDY_SIZES */
269
 
        ibool*  lru)    /* in: pointer to a variable that will be assigned
270
 
                        TRUE if storage was allocated from the LRU list
271
 
                        and buf_pool_mutex was temporarily released,
272
 
                        or NULL if the LRU list should not be used */
273
 
{
274
 
        buf_block_t*    block;
275
 
 
276
 
        ut_ad(buf_pool_mutex_own());
277
 
        ut_ad(!mutex_own(&buf_pool_zip_mutex));
278
 
 
279
 
        if (i < BUF_BUDDY_SIZES) {
280
 
                /* Try to allocate from the buddy system. */
281
 
                block = buf_buddy_alloc_zip(i);
282
 
 
283
 
                if (block) {
284
 
 
285
 
                        goto func_exit;
286
 
                }
287
 
        }
288
 
 
289
 
        /* Try allocating from the buf_pool->free list. */
290
 
        block = buf_LRU_get_free_only();
291
 
 
292
 
        if (block) {
293
 
 
294
 
                goto alloc_big;
295
 
        }
296
 
 
297
 
        if (!lru) {
298
 
 
299
 
                return(NULL);
300
 
        }
301
 
 
302
 
        /* Try replacing an uncompressed page in the buffer pool. */
303
 
        buf_pool_mutex_exit();
304
 
        block = buf_LRU_get_free_block(0);
305
 
        *lru = TRUE;
306
 
        buf_pool_mutex_enter();
307
 
 
308
 
alloc_big:
309
 
        buf_buddy_block_register(block);
310
 
 
311
 
        block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES);
312
 
 
313
 
func_exit:
314
 
        buf_buddy_stat[i].used++;
315
 
        return(block);
316
 
}
317
 
 
318
 
/**************************************************************************
319
 
Try to relocate the control block of a compressed page. */
320
 
static
321
 
ibool
322
 
buf_buddy_relocate_block(
323
 
/*=====================*/
324
 
                                /* out: TRUE if relocated */
325
 
        buf_page_t*     bpage,  /* in: block to relocate */
326
 
        buf_page_t*     dpage)  /* in: free block to relocate to */
327
 
{
328
 
        buf_page_t*     b;
329
 
 
330
 
        ut_ad(buf_pool_mutex_own());
331
 
 
332
 
        switch (buf_page_get_state(bpage)) {
333
 
        case BUF_BLOCK_ZIP_FREE:
334
 
        case BUF_BLOCK_NOT_USED:
335
 
        case BUF_BLOCK_READY_FOR_USE:
336
 
        case BUF_BLOCK_FILE_PAGE:
337
 
        case BUF_BLOCK_MEMORY:
338
 
        case BUF_BLOCK_REMOVE_HASH:
339
 
                ut_error;
340
 
        case BUF_BLOCK_ZIP_DIRTY:
341
 
                /* Cannot relocate dirty pages. */
342
 
                return(FALSE);
343
 
 
344
 
        case BUF_BLOCK_ZIP_PAGE:
345
 
                break;
346
 
        }
347
 
 
348
 
        mutex_enter(&buf_pool_zip_mutex);
349
 
 
350
 
        if (!buf_page_can_relocate(bpage)) {
351
 
                mutex_exit(&buf_pool_zip_mutex);
352
 
                return(FALSE);
353
 
        }
354
 
 
355
 
        buf_relocate(bpage, dpage);
356
 
        ut_d(bpage->state = BUF_BLOCK_ZIP_FREE);
357
 
 
358
 
        /* relocate buf_pool->zip_clean */
359
 
        b = UT_LIST_GET_PREV(list, dpage);
360
 
        UT_LIST_REMOVE(list, buf_pool->zip_clean, dpage);
361
 
 
362
 
        if (b) {
363
 
                UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, dpage);
364
 
        } else {
365
 
                UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage);
366
 
        }
367
 
 
368
 
        mutex_exit(&buf_pool_zip_mutex);
369
 
        return(TRUE);
370
 
}
371
 
 
372
 
/**************************************************************************
373
 
Try to relocate a block. */
374
 
static
375
 
ibool
376
 
buf_buddy_relocate(
377
 
/*===============*/
378
 
                        /* out: TRUE if relocated */
379
 
        void*   src,    /* in: block to relocate */
380
 
        void*   dst,    /* in: free block to relocate to */
381
 
        ulint   i)      /* in: index of buf_pool->zip_free[] */
382
 
{
383
 
        buf_page_t*     bpage;
384
 
        const ulint     size    = BUF_BUDDY_LOW << i;
385
 
        ullint          usec    = ut_time_us(NULL);
386
 
 
387
 
        ut_ad(buf_pool_mutex_own());
388
 
        ut_ad(!mutex_own(&buf_pool_zip_mutex));
389
 
        ut_ad(!ut_align_offset(src, size));
390
 
        ut_ad(!ut_align_offset(dst, size));
391
 
        UNIV_MEM_ASSERT_W(dst, size);
392
 
 
393
 
        /* We assume that all memory from buf_buddy_alloc()
394
 
        is used for either compressed pages or buf_page_t
395
 
        objects covering compressed pages. */
396
 
 
397
 
        /* We look inside the allocated objects returned by
398
 
        buf_buddy_alloc() and assume that anything of
399
 
        PAGE_ZIP_MIN_SIZE or larger is a compressed page that contains
400
 
        a valid space_id and page_no in the page header.  Should the
401
 
        fields be invalid, we will be unable to relocate the block.
402
 
        We also assume that anything that fits sizeof(buf_page_t)
403
 
        actually is a properly initialized buf_page_t object. */
404
 
 
405
 
        if (size >= PAGE_ZIP_MIN_SIZE) {
406
 
                /* This is a compressed page. */
407
 
                mutex_t*        mutex;
408
 
 
409
 
                /* The src block may be split into smaller blocks,
410
 
                some of which may be free.  Thus, the
411
 
                mach_read_from_4() calls below may attempt to read
412
 
                from free memory.  The memory is "owned" by the buddy
413
 
                allocator (and it has been allocated from the buffer
414
 
                pool), so there is nothing wrong about this.  The
415
 
                mach_read_from_4() calls here will only trigger bogus
416
 
                Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
417
 
                bpage = buf_page_hash_get(
418
 
                        mach_read_from_4((const byte*) src
419
 
                                         + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID),
420
 
                        mach_read_from_4((const byte*) src
421
 
                                         + FIL_PAGE_OFFSET));
422
 
 
423
 
                if (!bpage || bpage->zip.data != src) {
424
 
                        /* The block has probably been freshly
425
 
                        allocated by buf_LRU_get_free_block() but not
426
 
                        added to buf_pool->page_hash yet.  Obviously,
427
 
                        it cannot be relocated. */
428
 
 
429
 
                        return(FALSE);
430
 
                }
431
 
 
432
 
                if (page_zip_get_size(&bpage->zip) != size) {
433
 
                        /* The block is of different size.  We would
434
 
                        have to relocate all blocks covered by src.
435
 
                        For the sake of simplicity, give up. */
436
 
                        ut_ad(page_zip_get_size(&bpage->zip) < size);
437
 
 
438
 
                        return(FALSE);
439
 
                }
440
 
 
441
 
                /* The block must have been allocated, but it may
442
 
                contain uninitialized data. */
443
 
                UNIV_MEM_ASSERT_W(src, size);
444
 
 
445
 
                mutex = buf_page_get_mutex(bpage);
446
 
 
447
 
                mutex_enter(mutex);
448
 
 
449
 
                if (buf_page_can_relocate(bpage)) {
450
 
                        /* Relocate the compressed page. */
451
 
                        ut_a(bpage->zip.data == src);
452
 
                        memcpy(dst, src, size);
453
 
                        bpage->zip.data = dst;
454
 
                        mutex_exit(mutex);
455
 
success:
456
 
                        UNIV_MEM_INVALID(src, size);
457
 
                        {
458
 
                                buf_buddy_stat_t*       buddy_stat
459
 
                                        = &buf_buddy_stat[i];
460
 
                                buddy_stat->relocated++;
461
 
                                buddy_stat->relocated_usec
462
 
                                        += ut_time_us(NULL) - usec;
463
 
                        }
464
 
                        return(TRUE);
465
 
                }
466
 
 
467
 
                mutex_exit(mutex);
468
 
        } else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
469
 
                /* This must be a buf_page_t object. */
470
 
                UNIV_MEM_ASSERT_RW(src, size);
471
 
                if (buf_buddy_relocate_block(src, dst)) {
472
 
 
473
 
                        goto success;
474
 
                }
475
 
        }
476
 
 
477
 
        return(FALSE);
478
 
}
479
 
 
480
 
/**************************************************************************
481
 
Deallocate a block. */
482
 
UNIV_INTERN
483
 
void
484
 
buf_buddy_free_low(
485
 
/*===============*/
486
 
        void*   buf,    /* in: block to be freed, must not be
487
 
                        pointed to by the buffer pool */
488
 
        ulint   i)      /* in: index of buf_pool->zip_free[] */
489
 
{
490
 
        buf_page_t*     bpage;
491
 
        buf_page_t*     buddy;
492
 
 
493
 
        ut_ad(buf_pool_mutex_own());
494
 
        ut_ad(!mutex_own(&buf_pool_zip_mutex));
495
 
        ut_ad(i <= BUF_BUDDY_SIZES);
496
 
        ut_ad(buf_buddy_stat[i].used > 0);
497
 
 
498
 
        buf_buddy_stat[i].used--;
499
 
recombine:
500
 
        UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
501
 
        ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
502
 
 
503
 
        if (i == BUF_BUDDY_SIZES) {
504
 
                buf_buddy_block_free(buf);
505
 
                return;
506
 
        }
507
 
 
508
 
        ut_ad(i < BUF_BUDDY_SIZES);
509
 
        ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i));
510
 
        ut_ad(!buf_pool_contains_zip(buf));
511
 
 
512
 
        /* Try to combine adjacent blocks. */
513
 
 
514
 
        buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
515
 
 
516
 
#ifndef UNIV_DEBUG_VALGRIND
517
 
        /* Valgrind would complain about accessing free memory. */
518
 
 
519
 
        if (buddy->state != BUF_BLOCK_ZIP_FREE) {
520
 
 
521
 
                goto buddy_nonfree;
522
 
        }
523
 
 
524
 
        /* The field buddy->state can only be trusted for free blocks.
525
 
        If buddy->state == BUF_BLOCK_ZIP_FREE, the block is free if
526
 
        it is in the free list. */
527
 
#endif /* !UNIV_DEBUG_VALGRIND */
528
 
 
529
 
        for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); bpage; ) {
530
 
                UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
531
 
                ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
532
 
 
533
 
                if (bpage == buddy) {
534
 
buddy_free:
535
 
                        /* The buddy is free: recombine */
536
 
                        buf_buddy_remove_from_free(bpage, i);
537
 
buddy_free2:
538
 
                        ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
539
 
                        ut_ad(!buf_pool_contains_zip(buddy));
540
 
                        i++;
541
 
                        buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
542
 
 
543
 
                        goto recombine;
544
 
                }
545
 
 
546
 
                ut_a(bpage != buf);
547
 
 
548
 
                {
549
 
                        buf_page_t*     next = UT_LIST_GET_NEXT(list, bpage);
550
 
                        UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
551
 
                        bpage = next;
552
 
                }
553
 
        }
554
 
 
555
 
#ifndef UNIV_DEBUG_VALGRIND
556
 
buddy_nonfree:
557
 
        /* Valgrind would complain about accessing free memory. */
558
 
        ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]));
559
 
#endif /* UNIV_DEBUG_VALGRIND */
560
 
 
561
 
        /* The buddy is not free. Is there a free block of this size? */
562
 
        bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
563
 
 
564
 
        if (bpage) {
565
 
                /* Remove the block from the free list, because a successful
566
 
                buf_buddy_relocate() will overwrite bpage->list. */
567
 
 
568
 
                UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
569
 
                buf_buddy_remove_from_free(bpage, i);
570
 
 
571
 
                /* Try to relocate the buddy of buf to the free block. */
572
 
                if (buf_buddy_relocate(buddy, bpage, i)) {
573
 
 
574
 
                        ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
575
 
                        goto buddy_free2;
576
 
                }
577
 
 
578
 
                buf_buddy_add_to_free(bpage, i);
579
 
 
580
 
                /* Try to relocate the buddy of the free block to buf. */
581
 
                buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
582
 
                                                    BUF_BUDDY_LOW << i);
583
 
 
584
 
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
585
 
                {
586
 
                        const buf_page_t* b;
587
 
 
588
 
                        /* The buddy must not be (completely) free, because
589
 
                        we always recombine adjacent free blocks.
590
 
                        (Parts of the buddy can be free in
591
 
                        buf_pool->zip_free[j] with j < i.)*/
592
 
                        for (b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
593
 
                             b; b = UT_LIST_GET_NEXT(list, b)) {
594
 
 
595
 
                                ut_a(b != buddy);
596
 
                        }
597
 
                }
598
 
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
599
 
 
600
 
                if (buf_buddy_relocate(buddy, buf, i)) {
601
 
 
602
 
                        buf = bpage;
603
 
                        UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
604
 
                        ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
605
 
                        goto buddy_free;
606
 
                }
607
 
        }
608
 
 
609
 
        /* Free the block to the buddy list. */
610
 
        bpage = buf;
611
 
#ifdef UNIV_DEBUG
612
 
        if (i < buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)) {
613
 
                /* This area has most likely been allocated for at
614
 
                least one compressed-only block descriptor.  Check
615
 
                that there are no live objects in the area.  This is
616
 
                not a complete check: it may yield false positives as
617
 
                well as false negatives.  Also, due to buddy blocks
618
 
                being recombined, it is possible (although unlikely)
619
 
                that this branch is never reached. */
620
 
 
621
 
                char* c;
622
 
 
623
 
# ifndef UNIV_DEBUG_VALGRIND
624
 
                /* Valgrind would complain about accessing
625
 
                uninitialized memory.  Besides, Valgrind performs a
626
 
                more exhaustive check, at every memory access. */
627
 
                const buf_page_t* b = buf;
628
 
                const buf_page_t* const b_end = (buf_page_t*)
629
 
                        ((char*) b + (BUF_BUDDY_LOW << i));
630
 
 
631
 
                for (; b < b_end; b++) {
632
 
                        /* Avoid false positives (and cause false
633
 
                        negatives) by checking for b->space < 1000. */
634
 
 
635
 
                        if ((b->state == BUF_BLOCK_ZIP_PAGE
636
 
                             || b->state == BUF_BLOCK_ZIP_DIRTY)
637
 
                            && b->space > 0 && b->space < 1000) {
638
 
                                fprintf(stderr,
639
 
                                        "buddy dirty %p %u (%u,%u) %p,%lu\n",
640
 
                                        (void*) b,
641
 
                                        b->state, b->space, b->offset,
642
 
                                        buf, i);
643
 
                        }
644
 
                }
645
 
# endif /* !UNIV_DEBUG_VALGRIND */
646
 
 
647
 
                /* Scramble the block.  This should make any pointers
648
 
                invalid and trigger a segmentation violation.  Because
649
 
                the scrambling can be reversed, it may be possible to
650
 
                track down the object pointing to the freed data by
651
 
                dereferencing the unscrambled bpage->LRU or
652
 
                bpage->list pointers. */
653
 
                for (c = (char*) buf + (BUF_BUDDY_LOW << i);
654
 
                     c-- > (char*) buf; ) {
655
 
                        *c = ~*c ^ i;
656
 
                }
657
 
        } else {
658
 
                /* Fill large blocks with a constant pattern. */
659
 
                memset(bpage, i, BUF_BUDDY_LOW << i);
660
 
        }
661
 
#endif /* UNIV_DEBUG */
662
 
        bpage->state = BUF_BLOCK_ZIP_FREE;
663
 
        buf_buddy_add_to_free(bpage, i);
664
 
}