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];
48
37
/**********************************************************************//**
49
38
Get the offset of the buddy of a compressed page frame.
50
39
@return the buddy relative of page */
74
63
buf_buddy_add_to_free(
75
64
/*==================*/
76
buf_page_t* bpage, /*!< in,own: block to be freed */
77
ulint i) /*!< in: index of buf_pool->zip_free[] */
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[] */
79
70
#ifdef UNIV_DEBUG_VALGRIND
80
71
buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
82
73
if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i);
83
74
#endif /* UNIV_DEBUG_VALGRIND */
85
ut_ad(buf_pool_mutex_own());
76
ut_ad(buf_pool_mutex_own(buf_pool));
86
77
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
87
78
ut_ad(buf_pool->zip_free[i].start != bpage);
88
79
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
100
91
buf_buddy_remove_from_free(
101
92
/*=======================*/
102
buf_page_t* bpage, /*!< in: block to be removed */
103
ulint i) /*!< in: index of buf_pool->zip_free[] */
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[] */
105
98
#ifdef UNIV_DEBUG_VALGRIND
106
99
buf_page_t* prev = UT_LIST_GET_PREV(list, bpage);
113
106
ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
114
107
#endif /* UNIV_DEBUG_VALGRIND */
116
ut_ad(buf_pool_mutex_own());
109
ut_ad(buf_pool_mutex_own(buf_pool));
117
110
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
118
111
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
131
124
buf_buddy_alloc_zip(
132
125
/*================*/
133
ulint i) /*!< in: index of buf_pool->zip_free[] */
126
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
127
ulint i) /*!< in: index of buf_pool->zip_free[] */
135
129
buf_page_t* bpage;
137
ut_ad(buf_pool_mutex_own());
131
ut_ad(buf_pool_mutex_own(buf_pool));
138
132
ut_a(i < BUF_BUDDY_SIZES);
140
134
#ifndef UNIV_DEBUG_VALGRIND
149
143
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
150
144
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
152
buf_buddy_remove_from_free(bpage, i);
146
buf_buddy_remove_from_free(buf_pool, bpage, i);
153
147
} else if (i + 1 < BUF_BUDDY_SIZES) {
154
148
/* Attempt to split. */
155
bpage = buf_buddy_alloc_zip(i + 1);
149
bpage = buf_buddy_alloc_zip(buf_pool, i + 1);
158
152
buf_page_t* buddy = (buf_page_t*)
159
153
(((char*) bpage) + (BUF_BUDDY_LOW << i));
161
ut_ad(!buf_pool_contains_zip(buddy));
155
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
162
156
ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
163
157
buddy->state = BUF_BLOCK_ZIP_FREE;
164
buf_buddy_add_to_free(buddy, i);
158
buf_buddy_add_to_free(buf_pool, buddy, i);
183
177
buf_buddy_block_free(
184
178
/*=================*/
185
void* buf) /*!< in: buffer frame to deallocate */
179
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
180
void* buf) /*!< in: buffer frame to deallocate */
187
182
const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf);
188
183
buf_page_t* bpage;
189
184
buf_block_t* block;
191
ut_ad(buf_pool_mutex_own());
192
ut_ad(!mutex_own(&buf_pool_zip_mutex));
186
ut_ad(buf_pool_mutex_own(buf_pool));
187
ut_ad(!mutex_own(&buf_pool->zip_mutex));
193
188
ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE));
195
190
HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage,
211
206
buf_LRU_block_free_non_file_page(block);
212
207
mutex_exit(&block->mutex);
214
ut_ad(buf_buddy_n_frames > 0);
215
ut_d(buf_buddy_n_frames--);
209
ut_ad(buf_pool->buddy_n_frames > 0);
210
ut_d(buf_pool->buddy_n_frames--);
218
213
/**********************************************************************//**
223
218
/*=====================*/
224
219
buf_block_t* block) /*!< in: buffer frame to allocate */
221
buf_pool_t* buf_pool = buf_pool_from_block(block);
226
222
const ulint fold = BUF_POOL_ZIP_FOLD(block);
227
ut_ad(buf_pool_mutex_own());
228
ut_ad(!mutex_own(&buf_pool_zip_mutex));
223
ut_ad(buf_pool_mutex_own(buf_pool));
224
ut_ad(!mutex_own(&buf_pool->zip_mutex));
229
225
ut_ad(buf_block_get_state(block) == BUF_BLOCK_READY_FOR_USE);
231
227
buf_block_set_state(block, BUF_BLOCK_MEMORY);
238
234
ut_d(block->page.in_zip_hash = TRUE);
239
235
HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
241
ut_d(buf_buddy_n_frames++);
237
ut_d(buf_pool->buddy_n_frames++);
244
240
/**********************************************************************//**
249
245
buf_buddy_alloc_from(
250
246
/*=================*/
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[] */
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[] */
256
254
ulint offs = BUF_BUDDY_LOW << j;
257
255
ut_ad(j <= BUF_BUDDY_SIZES);
275
273
ut_list_node_313)
276
274
== BUF_BLOCK_ZIP_FREE)));
277
275
#endif /* !UNIV_DEBUG_VALGRIND */
278
buf_buddy_add_to_free(bpage, j);
276
buf_buddy_add_to_free(buf_pool, bpage, j);
284
282
/**********************************************************************//**
285
283
Allocate a block. The thread calling this function must hold
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.
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.
288
286
@return allocated block, possibly NULL if lru==NULL */
291
289
buf_buddy_alloc_low(
292
290
/*================*/
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 */
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 */
300
301
buf_block_t* block;
302
ut_ad(buf_pool_mutex_own());
303
ut_ad(!mutex_own(&buf_pool_zip_mutex));
303
ut_ad(buf_pool_mutex_own(buf_pool));
304
ut_ad(!mutex_own(&buf_pool->zip_mutex));
305
306
if (i < BUF_BUDDY_SIZES) {
306
307
/* Try to allocate from the buddy system. */
307
block = buf_buddy_alloc_zip(i);
308
block = buf_buddy_alloc_zip(buf_pool, i);
315
315
/* Try allocating from the buf_pool->free list. */
316
block = buf_LRU_get_free_only();
316
block = buf_LRU_get_free_only(buf_pool);
328
328
/* Try replacing an uncompressed page in the buffer pool. */
329
buf_pool_mutex_exit();
330
block = buf_LRU_get_free_block(0);
329
buf_pool_mutex_exit(buf_pool);
330
block = buf_LRU_get_free_block(buf_pool, 0);
332
buf_pool_mutex_enter();
332
buf_pool_mutex_enter(buf_pool);
335
335
buf_buddy_block_register(block);
337
block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES);
337
block = buf_buddy_alloc_from(
338
buf_pool, block->frame, i, BUF_BUDDY_SIZES);
340
buf_buddy_stat[i].used++;
341
buf_pool->buddy_stat[i].used++;
352
353
buf_page_t* dpage) /*!< in: free block to relocate to */
356
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
356
ut_ad(buf_pool_mutex_own());
358
ut_ad(buf_pool_mutex_own(buf_pool));
358
360
switch (buf_page_get_state(bpage)) {
359
361
case BUF_BLOCK_ZIP_FREE:
374
mutex_enter(&buf_pool_zip_mutex);
376
mutex_enter(&buf_pool->zip_mutex);
376
378
if (!buf_page_can_relocate(bpage)) {
377
mutex_exit(&buf_pool_zip_mutex);
379
mutex_exit(&buf_pool->zip_mutex);
405
407
buf_buddy_relocate(
406
408
/*===============*/
407
void* src, /*!< in: block to relocate */
408
void* dst, /*!< in: free block to relocate to */
409
ulint i) /*!< in: index of buf_pool->zip_free[] */
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[] */
411
415
buf_page_t* bpage;
412
416
const ulint size = BUF_BUDDY_LOW << i;
413
417
ullint usec = ut_time_us(NULL);
415
ut_ad(buf_pool_mutex_own());
416
ut_ad(!mutex_own(&buf_pool_zip_mutex));
419
ut_ad(buf_pool_mutex_own(buf_pool));
420
ut_ad(!mutex_own(&buf_pool->zip_mutex));
417
421
ut_ad(!ut_align_offset(src, size));
418
422
ut_ad(!ut_align_offset(dst, size));
419
423
UNIV_MEM_ASSERT_W(dst, size);
442
446
pool), so there is nothing wrong about this. The
443
447
mach_read_from_4() calls here will only trigger bogus
444
448
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
445
ulint space = mach_read_from_4(
446
(const byte*) src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
447
ulint page_no = mach_read_from_4(
448
(const byte*) src + FIL_PAGE_OFFSET);
449
/* Suppress Valgrind warnings about conditional jump
450
on uninitialized value. */
451
UNIV_MEM_VALID(&space, sizeof space);
452
UNIV_MEM_VALID(&page_no, sizeof page_no);
453
bpage = buf_page_hash_get(space, page_no);
449
bpage = buf_page_hash_get(
451
mach_read_from_4((const byte*) src
452
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID),
453
mach_read_from_4((const byte*) src
455
456
if (!bpage || bpage->zip.data != src) {
456
457
/* The block has probably been freshly
465
ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
464
467
if (page_zip_get_size(&bpage->zip) != size) {
465
468
/* The block is of different size. We would
466
469
have to relocate all blocks covered by src.
488
491
UNIV_MEM_INVALID(src, size);
490
493
buf_buddy_stat_t* buddy_stat
491
= &buf_buddy_stat[i];
494
= &buf_pool->buddy_stat[i];
492
495
buddy_stat->relocated++;
493
496
buddy_stat->relocated_usec
494
497
+= ut_time_us(NULL) - usec;
499
502
mutex_exit(mutex);
500
503
} else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
501
504
/* This must be a buf_page_t object. */
502
#if UNIV_WORD_SIZE == 4
503
/* On 32-bit systems, there is no padding in
504
buf_page_t. On other systems, Valgrind could complain
505
about uninitialized pad bytes. */
506
505
UNIV_MEM_ASSERT_RW(src, size);
508
506
if (buf_buddy_relocate_block(src, dst)) {
521
519
buf_buddy_free_low(
522
520
/*===============*/
523
void* buf, /*!< in: block to be freed, must not be
524
pointed to by the buffer pool */
525
ulint i) /*!< in: index of buf_pool->zip_free[],
526
or BUF_BUDDY_SIZES */
521
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
522
void* buf, /*!< in: block to be freed, must not be
523
pointed to by the buffer pool */
524
ulint i) /*!< in: index of buf_pool->zip_free[],
525
or BUF_BUDDY_SIZES */
528
527
buf_page_t* bpage;
529
528
buf_page_t* buddy;
531
ut_ad(buf_pool_mutex_own());
532
ut_ad(!mutex_own(&buf_pool_zip_mutex));
530
ut_ad(buf_pool_mutex_own(buf_pool));
531
ut_ad(!mutex_own(&buf_pool->zip_mutex));
533
532
ut_ad(i <= BUF_BUDDY_SIZES);
534
ut_ad(buf_buddy_stat[i].used > 0);
533
ut_ad(buf_pool->buddy_stat[i].used > 0);
536
buf_buddy_stat[i].used--;
535
buf_pool->buddy_stat[i].used--;
538
537
UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
539
538
ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
541
540
if (i == BUF_BUDDY_SIZES) {
542
buf_buddy_block_free(buf);
541
buf_buddy_block_free(buf_pool, buf);
546
545
ut_ad(i < BUF_BUDDY_SIZES);
547
546
ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i));
548
ut_ad(!buf_pool_contains_zip(buf));
547
ut_ad(!buf_pool_contains_zip(buf_pool, buf));
550
549
/* Try to combine adjacent blocks. */
571
570
if (bpage == buddy) {
573
572
/* The buddy is free: recombine */
574
buf_buddy_remove_from_free(bpage, i);
573
buf_buddy_remove_from_free(buf_pool, bpage, i);
576
575
ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
577
ut_ad(!buf_pool_contains_zip(buddy));
576
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
579
578
buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
606
605
buf_buddy_relocate() will overwrite bpage->list. */
608
607
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
609
buf_buddy_remove_from_free(bpage, i);
608
buf_buddy_remove_from_free(buf_pool, bpage, i);
611
610
/* Try to relocate the buddy of buf to the free block. */
612
if (buf_buddy_relocate(buddy, bpage, i)) {
611
if (buf_buddy_relocate(buf_pool, buddy, bpage, i)) {
614
613
ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
615
614
goto buddy_free2;
618
buf_buddy_add_to_free(bpage, i);
617
buf_buddy_add_to_free(buf_pool, bpage, i);
620
619
/* Try to relocate the buddy of the free block to buf. */
621
620
buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
636
635
&& ut_list_node_313 != buddy)));
637
636
#endif /* !UNIV_DEBUG_VALGRIND */
639
if (buf_buddy_relocate(buddy, buf, i)) {
638
if (buf_buddy_relocate(buf_pool, buddy, buf, i)) {
642
641
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
700
699
#endif /* UNIV_DEBUG */
701
700
bpage->state = BUF_BLOCK_ZIP_FREE;
702
buf_buddy_add_to_free(bpage, i);
701
buf_buddy_add_to_free(buf_pool, bpage, i);