1
1
/*****************************************************************************
3
Copyright (C) 2006, 2010, Innobase Oy. All Rights Reserved.
3
Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
34
34
#include "buf0flu.h"
35
35
#include "page0zip.h"
37
/* Statistic counters */
40
/** Number of frames allocated from the buffer pool to the buddy system.
41
Protected by buf_pool_mutex. */
42
static ulint buf_buddy_n_frames;
43
#endif /* UNIV_DEBUG */
44
/** Statistics of the buddy system, indexed by block size.
45
Protected by buf_pool_mutex. */
46
UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1];
37
48
/**********************************************************************//**
38
49
Get the offset of the buddy of a compressed page frame.
39
50
@return the buddy relative of page */
63
74
buf_buddy_add_to_free(
64
75
/*==================*/
65
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
66
buf_page_t* bpage, /*!< in,own: block to be freed */
67
ulint i) /*!< in: index of
68
buf_pool->zip_free[] */
76
buf_page_t* bpage, /*!< in,own: block to be freed */
77
ulint i) /*!< in: index of buf_pool->zip_free[] */
70
79
#ifdef UNIV_DEBUG_VALGRIND
71
80
buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
73
82
if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i);
74
83
#endif /* UNIV_DEBUG_VALGRIND */
76
ut_ad(buf_pool_mutex_own(buf_pool));
85
ut_ad(buf_pool_mutex_own());
77
86
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
78
87
ut_ad(buf_pool->zip_free[i].start != bpage);
79
88
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
91
100
buf_buddy_remove_from_free(
92
101
/*=======================*/
93
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
94
buf_page_t* bpage, /*!< in: block to be removed */
95
ulint i) /*!< in: index of
96
buf_pool->zip_free[] */
102
buf_page_t* bpage, /*!< in: block to be removed */
103
ulint i) /*!< in: index of buf_pool->zip_free[] */
98
105
#ifdef UNIV_DEBUG_VALGRIND
99
106
buf_page_t* prev = UT_LIST_GET_PREV(list, bpage);
106
113
ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
107
114
#endif /* UNIV_DEBUG_VALGRIND */
109
ut_ad(buf_pool_mutex_own(buf_pool));
116
ut_ad(buf_pool_mutex_own());
110
117
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
111
118
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
124
131
buf_buddy_alloc_zip(
125
132
/*================*/
126
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
127
ulint i) /*!< in: index of buf_pool->zip_free[] */
133
ulint i) /*!< in: index of buf_pool->zip_free[] */
129
135
buf_page_t* bpage;
131
ut_ad(buf_pool_mutex_own(buf_pool));
137
ut_ad(buf_pool_mutex_own());
132
138
ut_a(i < BUF_BUDDY_SIZES);
134
140
#ifndef UNIV_DEBUG_VALGRIND
143
149
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
144
150
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
146
buf_buddy_remove_from_free(buf_pool, bpage, i);
152
buf_buddy_remove_from_free(bpage, i);
147
153
} else if (i + 1 < BUF_BUDDY_SIZES) {
148
154
/* Attempt to split. */
149
bpage = (buf_page_t *)buf_buddy_alloc_zip(buf_pool, i + 1);
155
bpage = buf_buddy_alloc_zip(i + 1);
152
158
buf_page_t* buddy = (buf_page_t*)
153
159
(((char*) bpage) + (BUF_BUDDY_LOW << i));
155
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
161
ut_ad(!buf_pool_contains_zip(buddy));
156
162
ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
157
163
buddy->state = BUF_BLOCK_ZIP_FREE;
158
buf_buddy_add_to_free(buf_pool, buddy, i);
164
buf_buddy_add_to_free(buddy, i);
177
183
buf_buddy_block_free(
178
184
/*=================*/
179
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
180
void* buf) /*!< in: buffer frame to deallocate */
185
void* buf) /*!< in: buffer frame to deallocate */
182
187
const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf);
183
188
buf_page_t* bpage;
184
189
buf_block_t* block;
186
ut_ad(buf_pool_mutex_own(buf_pool));
187
ut_ad(!mutex_own(&buf_pool->zip_mutex));
191
ut_ad(buf_pool_mutex_own());
192
ut_ad(!mutex_own(&buf_pool_zip_mutex));
188
193
ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE));
190
195
HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage,
206
211
buf_LRU_block_free_non_file_page(block);
207
212
mutex_exit(&block->mutex);
209
ut_ad(buf_pool->buddy_n_frames > 0);
210
ut_d(buf_pool->buddy_n_frames--);
214
ut_ad(buf_buddy_n_frames > 0);
215
ut_d(buf_buddy_n_frames--);
213
218
/**********************************************************************//**
218
223
/*=====================*/
219
224
buf_block_t* block) /*!< in: buffer frame to allocate */
221
buf_pool_t* buf_pool = buf_pool_from_block(block);
222
226
const ulint fold = BUF_POOL_ZIP_FOLD(block);
223
ut_ad(buf_pool_mutex_own(buf_pool));
224
ut_ad(!mutex_own(&buf_pool->zip_mutex));
227
ut_ad(buf_pool_mutex_own());
228
ut_ad(!mutex_own(&buf_pool_zip_mutex));
225
229
ut_ad(buf_block_get_state(block) == BUF_BLOCK_READY_FOR_USE);
227
231
buf_block_set_state(block, BUF_BLOCK_MEMORY);
234
238
ut_d(block->page.in_zip_hash = TRUE);
235
239
HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
237
ut_d(buf_pool->buddy_n_frames++);
241
ut_d(buf_buddy_n_frames++);
240
244
/**********************************************************************//**
245
249
buf_buddy_alloc_from(
246
250
/*=================*/
247
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
248
void* buf, /*!< in: a block that is free to use */
249
ulint i, /*!< in: index of
250
buf_pool->zip_free[] */
251
ulint j) /*!< in: size of buf as an index
252
of buf_pool->zip_free[] */
251
void* buf, /*!< in: a block that is free to use */
252
ulint i, /*!< in: index of buf_pool->zip_free[] */
253
ulint j) /*!< in: size of buf as an index
254
of buf_pool->zip_free[] */
254
256
ulint offs = BUF_BUDDY_LOW << j;
255
257
ut_ad(j <= BUF_BUDDY_SIZES);
273
275
ut_list_node_313)
274
276
== BUF_BLOCK_ZIP_FREE)));
275
277
#endif /* !UNIV_DEBUG_VALGRIND */
276
buf_buddy_add_to_free(buf_pool, bpage, j);
278
buf_buddy_add_to_free(bpage, j);
282
284
/**********************************************************************//**
283
285
Allocate a block. The thread calling this function must hold
284
buf_pool->mutex and must not hold buf_pool->zip_mutex or any block->mutex.
285
The buf_pool->mutex may only be released and reacquired if lru != NULL.
286
buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex.
287
The buf_pool_mutex may only be released and reacquired if lru != NULL.
286
288
@return allocated block, possibly NULL if lru==NULL */
289
291
buf_buddy_alloc_low(
290
292
/*================*/
291
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
292
ulint i, /*!< in: index of buf_pool->zip_free[],
293
or BUF_BUDDY_SIZES */
294
ibool* lru) /*!< in: pointer to a variable that
295
will be assigned TRUE if storage was
296
allocated from the LRU list and
297
buf_pool->mutex was temporarily
298
released, or NULL if the LRU list
299
should not be used */
293
ulint i, /*!< in: index of buf_pool->zip_free[],
294
or BUF_BUDDY_SIZES */
295
ibool* lru) /*!< in: pointer to a variable that will be assigned
296
TRUE if storage was allocated from the LRU list
297
and buf_pool_mutex was temporarily released,
298
or NULL if the LRU list should not be used */
301
300
buf_block_t* block;
303
ut_ad(buf_pool_mutex_own(buf_pool));
304
ut_ad(!mutex_own(&buf_pool->zip_mutex));
302
ut_ad(buf_pool_mutex_own());
303
ut_ad(!mutex_own(&buf_pool_zip_mutex));
306
305
if (i < BUF_BUDDY_SIZES) {
307
306
/* Try to allocate from the buddy system. */
308
block = (buf_block_t *)buf_buddy_alloc_zip(buf_pool, i);
307
block = buf_buddy_alloc_zip(i);
315
315
/* Try allocating from the buf_pool->free list. */
316
block = buf_LRU_get_free_only(buf_pool);
316
block = buf_LRU_get_free_only();
328
328
/* Try replacing an uncompressed page in the buffer pool. */
329
buf_pool_mutex_exit(buf_pool);
330
block = buf_LRU_get_free_block(buf_pool, 0);
329
buf_pool_mutex_exit();
330
block = buf_LRU_get_free_block(0);
332
buf_pool_mutex_enter(buf_pool);
332
buf_pool_mutex_enter();
335
335
buf_buddy_block_register(block);
337
block = (buf_block_t *)buf_buddy_alloc_from(buf_pool, block->frame,
337
block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES);
341
buf_pool->buddy_stat[i].used++;
340
buf_buddy_stat[i].used++;
353
352
buf_page_t* dpage) /*!< in: free block to relocate to */
356
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
358
ut_ad(buf_pool_mutex_own(buf_pool));
356
ut_ad(buf_pool_mutex_own());
360
358
switch (buf_page_get_state(bpage)) {
361
359
case BUF_BLOCK_ZIP_FREE:
376
mutex_enter(&buf_pool->zip_mutex);
374
mutex_enter(&buf_pool_zip_mutex);
378
376
if (!buf_page_can_relocate(bpage)) {
379
mutex_exit(&buf_pool->zip_mutex);
377
mutex_exit(&buf_pool_zip_mutex);
393
391
UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage);
396
UNIV_MEM_INVALID(bpage, sizeof *bpage);
398
mutex_exit(&buf_pool->zip_mutex);
394
mutex_exit(&buf_pool_zip_mutex);
407
403
buf_buddy_relocate(
408
404
/*===============*/
409
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
410
void* src, /*!< in: block to relocate */
411
void* dst, /*!< in: free block to relocate to */
412
ulint i) /*!< in: index of
413
buf_pool->zip_free[] */
405
void* src, /*!< in: block to relocate */
406
void* dst, /*!< in: free block to relocate to */
407
ulint i) /*!< in: index of buf_pool->zip_free[] */
415
409
buf_page_t* bpage;
418
410
const ulint size = BUF_BUDDY_LOW << i;
419
411
ullint usec = ut_time_us(NULL);
421
ut_ad(buf_pool_mutex_own(buf_pool));
422
ut_ad(!mutex_own(&buf_pool->zip_mutex));
413
ut_ad(buf_pool_mutex_own());
414
ut_ad(!mutex_own(&buf_pool_zip_mutex));
423
415
ut_ad(!ut_align_offset(src, size));
424
416
ut_ad(!ut_align_offset(dst, size));
425
417
UNIV_MEM_ASSERT_W(dst, size);
448
440
pool), so there is nothing wrong about this. The
449
441
mach_read_from_4() calls here will only trigger bogus
450
442
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
451
space = mach_read_from_4(
452
(const byte*) src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
453
page_no = mach_read_from_4(
454
(const byte*) src + FIL_PAGE_OFFSET);
455
/* Suppress Valgrind warnings about conditional jump
456
on uninitialized value. */
457
UNIV_MEM_VALID(&space, sizeof space);
458
UNIV_MEM_VALID(&page_no, sizeof page_no);
459
bpage = buf_page_hash_get(buf_pool, space, page_no);
443
bpage = buf_page_hash_get(
444
mach_read_from_4((const byte*) src
445
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID),
446
mach_read_from_4((const byte*) src
461
449
if (!bpage || bpage->zip.data != src) {
462
450
/* The block has probably been freshly
470
ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
472
458
if (page_zip_get_size(&bpage->zip) != size) {
473
459
/* The block is of different size. We would
474
460
have to relocate all blocks covered by src.
490
476
/* Relocate the compressed page. */
491
477
ut_a(bpage->zip.data == src);
492
478
memcpy(dst, src, size);
493
bpage->zip.data = (page_zip_t *)dst;
479
bpage->zip.data = dst;
494
480
mutex_exit(mutex);
496
482
UNIV_MEM_INVALID(src, size);
498
484
buf_buddy_stat_t* buddy_stat
499
= &buf_pool->buddy_stat[i];
485
= &buf_buddy_stat[i];
500
486
buddy_stat->relocated++;
501
487
buddy_stat->relocated_usec
502
488
+= ut_time_us(NULL) - usec;
507
493
mutex_exit(mutex);
508
494
} else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
509
495
/* This must be a buf_page_t object. */
510
#if UNIV_WORD_SIZE == 4
511
/* On 32-bit systems, there is no padding in
512
buf_page_t. On other systems, Valgrind could complain
513
about uninitialized pad bytes. */
514
496
UNIV_MEM_ASSERT_RW(src, size);
516
if (buf_buddy_relocate_block((buf_page_t *)src, (buf_page_t *)dst)) {
497
if (buf_buddy_relocate_block(src, dst)) {
529
510
buf_buddy_free_low(
530
511
/*===============*/
531
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
532
void* buf, /*!< in: block to be freed, must not be
533
pointed to by the buffer pool */
534
ulint i) /*!< in: index of buf_pool->zip_free[],
535
or BUF_BUDDY_SIZES */
512
void* buf, /*!< in: block to be freed, must not be
513
pointed to by the buffer pool */
514
ulint i) /*!< in: index of buf_pool->zip_free[],
515
or BUF_BUDDY_SIZES */
537
517
buf_page_t* bpage;
538
518
buf_page_t* buddy;
540
ut_ad(buf_pool_mutex_own(buf_pool));
541
ut_ad(!mutex_own(&buf_pool->zip_mutex));
520
ut_ad(buf_pool_mutex_own());
521
ut_ad(!mutex_own(&buf_pool_zip_mutex));
542
522
ut_ad(i <= BUF_BUDDY_SIZES);
543
ut_ad(buf_pool->buddy_stat[i].used > 0);
523
ut_ad(buf_buddy_stat[i].used > 0);
545
buf_pool->buddy_stat[i].used--;
525
buf_buddy_stat[i].used--;
547
527
UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
548
528
ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
550
530
if (i == BUF_BUDDY_SIZES) {
551
buf_buddy_block_free(buf_pool, buf);
531
buf_buddy_block_free(buf);
555
535
ut_ad(i < BUF_BUDDY_SIZES);
556
536
ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i));
557
ut_ad(!buf_pool_contains_zip(buf_pool, buf));
537
ut_ad(!buf_pool_contains_zip(buf));
559
539
/* Try to combine adjacent blocks. */
580
560
if (bpage == buddy) {
582
562
/* The buddy is free: recombine */
583
buf_buddy_remove_from_free(buf_pool, bpage, i);
563
buf_buddy_remove_from_free(bpage, i);
585
565
ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
586
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
566
ut_ad(!buf_pool_contains_zip(buddy));
588
568
buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
615
595
buf_buddy_relocate() will overwrite bpage->list. */
617
597
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
618
buf_buddy_remove_from_free(buf_pool, bpage, i);
598
buf_buddy_remove_from_free(bpage, i);
620
600
/* Try to relocate the buddy of buf to the free block. */
621
if (buf_buddy_relocate(buf_pool, buddy, bpage, i)) {
601
if (buf_buddy_relocate(buddy, bpage, i)) {
623
603
ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
624
604
goto buddy_free2;
627
buf_buddy_add_to_free(buf_pool, bpage, i);
607
buf_buddy_add_to_free(bpage, i);
629
609
/* Try to relocate the buddy of the free block to buf. */
630
610
buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
645
625
&& ut_list_node_313 != buddy)));
646
626
#endif /* !UNIV_DEBUG_VALGRIND */
648
if (buf_buddy_relocate(buf_pool, buddy, buf, i)) {
628
if (buf_buddy_relocate(buddy, buf, i)) {
651
631
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
709
689
#endif /* UNIV_DEBUG */
710
690
bpage->state = BUF_BLOCK_ZIP_FREE;
711
buf_buddy_add_to_free(buf_pool, bpage, i);
691
buf_buddy_add_to_free(bpage, i);