88
88
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
90
90
/********************************************************************//**
91
Insert a block in the flush_rbt and returns a pointer to its
92
predecessor or NULL if no predecessor. The ordering is maintained
93
on the basis of the <oldest_modification, space, offset> key.
94
@return pointer to the predecessor or NULL if no predecessor. */
97
buf_flush_insert_in_flush_rbt(
98
/*==========================*/
99
buf_page_t* bpage) /*!< in: bpage to be inserted. */
101
buf_page_t* prev = NULL;
102
const ib_rbt_node_t* c_node;
103
const ib_rbt_node_t* p_node;
105
ut_ad(buf_pool_mutex_own());
107
/* Insert this buffer into the rbt. */
108
c_node = rbt_insert(buf_pool->flush_rbt, &bpage, &bpage);
109
ut_a(c_node != NULL);
111
/* Get the predecessor. */
112
p_node = rbt_prev(buf_pool->flush_rbt, c_node);
114
if (p_node != NULL) {
115
prev = *rbt_value(buf_page_t*, p_node);
122
/********************************************************************//**
123
Delete a bpage from the flush_rbt. */
126
buf_flush_delete_from_flush_rbt(
127
/*============================*/
128
buf_page_t* bpage) /*!< in: bpage to be removed. */
133
ut_ad(buf_pool_mutex_own());
134
ret = rbt_delete(buf_pool->flush_rbt, &bpage);
138
/********************************************************************//**
139
Compare two modified blocks in the buffer pool. The key for comparison
141
key = <oldest_modification, space, offset>
142
This comparison is used to maintian ordering of blocks in the
144
Note that for the purpose of flush_rbt, we only need to order blocks
145
on the oldest_modification. The other two fields are used to uniquely
147
@return < 0 if b2 < b1, 0 if b2 == b1, > 0 if b2 > b1 */
152
const void* p1, /*!< in: block1 */
153
const void* p2) /*!< in: block2 */
160
const buf_page_t* b1 = *(const buf_page_t**) p1;
161
const buf_page_t* b2 = *(const buf_page_t**) p2;
166
ut_ad(b1->in_flush_list);
167
ut_ad(b2->in_flush_list);
169
if (b2->oldest_modification
170
> b1->oldest_modification) {
174
if (b2->oldest_modification
175
< b1->oldest_modification) {
179
/* If oldest_modification is same then decide on the space. */
180
ret = (int)(b2->space - b1->space);
182
/* Or else decide ordering on the offset field. */
183
return(ret ? ret : (int)(b2->offset - b1->offset));
186
/********************************************************************//**
187
Initialize the red-black tree to speed up insertions into the flush_list
188
during recovery process. Should be called at the start of recovery
189
process before any page has been read/written. */
192
buf_flush_init_flush_rbt(void)
193
/*==========================*/
195
buf_pool_mutex_enter();
197
/* Create red black tree for speedy insertions in flush list. */
198
buf_pool->flush_rbt = rbt_create(sizeof(buf_page_t*),
199
buf_flush_block_cmp);
200
buf_pool_mutex_exit();
203
/********************************************************************//**
204
Frees up the red-black tree. */
207
buf_flush_free_flush_rbt(void)
208
/*==========================*/
210
buf_pool_mutex_enter();
212
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
213
ut_a(buf_flush_validate_low());
214
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
216
rbt_free(buf_pool->flush_rbt);
217
buf_pool->flush_rbt = NULL;
219
buf_pool_mutex_exit();
222
/********************************************************************//**
223
91
Inserts a modified block into the flush list. */
275
136
ut_d(block->page.in_flush_list = TRUE);
279
/* For the most part when this function is called the flush_rbt
280
should not be NULL. In a very rare boundary case it is possible
281
that the flush_rbt has already been freed by the recovery thread
282
before the last page was hooked up in the flush_list by the
283
io-handler thread. In that case we'll just do a simple
284
linear search in the else block. */
285
if (buf_pool->flush_rbt) {
287
prev_b = buf_flush_insert_in_flush_rbt(&block->page);
291
b = UT_LIST_GET_FIRST(buf_pool->flush_list);
293
while (b && b->oldest_modification
294
> block->page.oldest_modification) {
295
ut_ad(b->in_flush_list);
297
b = UT_LIST_GET_NEXT(list, b);
139
b = UT_LIST_GET_FIRST(buf_pool->flush_list);
141
while (b && b->oldest_modification > block->page.oldest_modification) {
142
ut_ad(b->in_flush_list);
144
b = UT_LIST_GET_NEXT(list, b);
301
147
if (prev_b == NULL) {
430
268
/********************************************************************//**
431
Relocates a buffer control block on the flush_list.
432
Note that it is assumed that the contents of bpage has already been
436
buf_flush_relocate_on_flush_list(
437
/*=============================*/
438
buf_page_t* bpage, /*!< in/out: control block being moved */
439
buf_page_t* dpage) /*!< in/out: destination block */
442
buf_page_t* prev_b = NULL;
444
ut_ad(buf_pool_mutex_own());
446
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
448
ut_ad(bpage->in_flush_list);
449
ut_ad(dpage->in_flush_list);
451
/* If recovery is active we must swap the control blocks in
452
the flush_rbt as well. */
453
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
454
buf_flush_delete_from_flush_rbt(bpage);
455
prev_b = buf_flush_insert_in_flush_rbt(dpage);
458
/* Must be done after we have removed it from the flush_rbt
459
because we assert on in_flush_list in comparison function. */
460
ut_d(bpage->in_flush_list = FALSE);
462
prev = UT_LIST_GET_PREV(list, bpage);
463
UT_LIST_REMOVE(list, buf_pool->flush_list, bpage);
466
ut_ad(prev->in_flush_list);
467
UT_LIST_INSERT_AFTER(
469
buf_pool->flush_list,
474
buf_pool->flush_list,
478
/* Just an extra check. Previous in flush_list
479
should be the same control block as in flush_rbt. */
480
ut_a(!buf_pool->flush_rbt || prev_b == prev);
482
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
483
ut_a(buf_flush_validate_low());
484
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
487
/********************************************************************//**
488
269
Updates the flush system data structures when a write is completed. */
1588
1369
buf_flush_validate_low(void)
1589
1370
/*========================*/
1592
const ib_rbt_node_t* rnode = NULL;
1594
1374
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list,
1595
1375
ut_ad(ut_list_node_313->in_flush_list));
1597
1377
bpage = UT_LIST_GET_FIRST(buf_pool->flush_list);
1599
/* If we are in recovery mode i.e.: flush_rbt != NULL
1600
then each block in the flush_list must also be present
1601
in the flush_rbt. */
1602
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
1603
rnode = rbt_first(buf_pool->flush_rbt);
1606
1379
while (bpage != NULL) {
1607
1380
const ib_uint64_t om = bpage->oldest_modification;
1608
1381
ut_ad(bpage->in_flush_list);
1609
1382
ut_a(buf_page_in_file(bpage));
1612
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
1614
buf_page_t* rpage = *rbt_value(buf_page_t*,
1617
ut_a(rpage == bpage);
1618
rnode = rbt_next(buf_pool->flush_rbt, rnode);
1621
1385
bpage = UT_LIST_GET_NEXT(list, bpage);
1623
1387
ut_a(!bpage || om >= bpage->oldest_modification);
1626
/* By this time we must have exhausted the traversal of
1627
flush_rbt (if active) as well. */
1628
ut_a(rnode == NULL);