Commit c88ae401 authored by inaam's avatar inaam

branches/innodb+ issue#115

This is to fix issues introduced by recovery enhancements committed
through r2993. The fix is to update flush_rbt whenever flush_list is
manipulated because of buf_page/buf_block relocation.

rb://54

Reviewed by: Marko
parent 396b13f9
...@@ -365,6 +365,8 @@ buf_buddy_relocate_block( ...@@ -365,6 +365,8 @@ buf_buddy_relocate_block(
UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage); UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage);
} }
UNIV_MEM_INVALID(bpage, sizeof *bpage);
mutex_exit(&buf_pool_zip_mutex); mutex_exit(&buf_pool_zip_mutex);
return(TRUE); return(TRUE);
} }
......
...@@ -1070,8 +1070,6 @@ buf_relocate( ...@@ -1070,8 +1070,6 @@ buf_relocate(
HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage); HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage); HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage);
UNIV_MEM_INVALID(bpage, sizeof *bpage);
} }
/************************************************************************ /************************************************************************
...@@ -2047,22 +2045,8 @@ buf_page_get_gen( ...@@ -2047,22 +2045,8 @@ buf_page_get_gen(
ut_ad(!block->page.in_flush_list); ut_ad(!block->page.in_flush_list);
} else { } else {
/* Relocate buf_pool->flush_list. */ /* Relocate buf_pool->flush_list. */
buf_page_t* b; buf_flush_relocate_on_flush_list(bpage,
&block->page);
b = UT_LIST_GET_PREV(list, &block->page);
ut_ad(block->page.in_flush_list);
UT_LIST_REMOVE(list, buf_pool->flush_list,
&block->page);
if (b) {
UT_LIST_INSERT_AFTER(
list, buf_pool->flush_list, b,
&block->page);
} else {
UT_LIST_ADD_FIRST(
list, buf_pool->flush_list,
&block->page);
}
} }
/* Buffer-fix, I/O-fix, and X-latch the block /* Buffer-fix, I/O-fix, and X-latch the block
...@@ -2077,6 +2061,9 @@ buf_page_get_gen( ...@@ -2077,6 +2061,9 @@ buf_page_get_gen(
buf_block_set_io_fix(block, BUF_IO_READ); buf_block_set_io_fix(block, BUF_IO_READ);
buf_pool->n_pend_unzip++; buf_pool->n_pend_unzip++;
rw_lock_x_lock(&block->lock); rw_lock_x_lock(&block->lock);
UNIV_MEM_INVALID(bpage, sizeof *bpage);
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
mutex_exit(&buf_pool_zip_mutex); mutex_exit(&buf_pool_zip_mutex);
......
...@@ -378,7 +378,6 @@ buf_flush_remove( ...@@ -378,7 +378,6 @@ buf_flush_remove(
ut_ad(buf_pool_mutex_own()); ut_ad(buf_pool_mutex_own());
ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(mutex_own(buf_page_get_mutex(bpage)));
ut_ad(bpage->in_flush_list); ut_ad(bpage->in_flush_list);
ut_d(bpage->in_flush_list = FALSE);
switch (buf_page_get_state(bpage)) { switch (buf_page_get_state(bpage)) {
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
...@@ -405,11 +404,76 @@ buf_flush_remove( ...@@ -405,11 +404,76 @@ buf_flush_remove(
buf_flush_delete_from_flush_rbt(bpage); buf_flush_delete_from_flush_rbt(bpage);
} }
/* Must be done after we have removed it from the flush_rbt
because we assert on in_flush_list in comparison function. */
ut_d(bpage->in_flush_list = FALSE);
bpage->oldest_modification = 0; bpage->oldest_modification = 0;
ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list)); ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list));
} }
/***********************************************************************
Relocates a buffer control block on the flush_list.
Note that it is assumed that the contents of bpage has already been
copied to dpage. */
UNIV_INTERN
void
buf_flush_relocate_on_flush_list(
/*=============================*/
buf_page_t* bpage, /* in/out: control block being moved */
buf_page_t* dpage) /* in/out: destination block */
{
buf_page_t* prev;
buf_page_t* prev_b = NULL;
ut_ad(buf_pool_mutex_own());
ut_ad(buf_page_in_file(bpage));
ut_ad(buf_page_in_file(dpage));
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
ut_ad(buf_page_get_state(dpage) != BUF_BLOCK_FILE_PAGE
|| mutex_own(buf_page_get_mutex(dpage)));
ut_ad(bpage->in_flush_list);
ut_ad(dpage->in_flush_list);
/* If recovery is active we must swap the control blocks in
the flush_rbt as well. */
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
buf_flush_delete_from_flush_rbt(bpage);
prev_b = buf_flush_insert_in_flush_rbt(dpage);
}
/* Must be done after we have removed it from the flush_rbt
because we assert on in_flush_list in comparison function. */
ut_d(bpage->in_flush_list = FALSE);
prev = UT_LIST_GET_PREV(list, bpage);
UT_LIST_REMOVE(list, buf_pool->flush_list, bpage);
if (prev) {
ut_ad(prev->in_flush_list);
UT_LIST_INSERT_AFTER(
list,
buf_pool->flush_list,
prev, dpage);
} else {
UT_LIST_ADD_FIRST(
list,
buf_pool->flush_list,
dpage);
}
/* Just an extra check. Previous in flush_list
should be the same control block as in flush_rbt. */
ut_a(!buf_pool->flush_rbt || prev_b == prev);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(buf_flush_validate_low());
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
}
/************************************************************************ /************************************************************************
Updates the flush system data structures when a write is completed. */ Updates the flush system data structures when a write is completed. */
UNIV_INTERN UNIV_INTERN
...@@ -1426,25 +1490,33 @@ buf_flush_validate_low(void) ...@@ -1426,25 +1490,33 @@ buf_flush_validate_low(void)
/*========================*/ /*========================*/
/* out: TRUE if ok */ /* out: TRUE if ok */
{ {
buf_page_t* bpage; buf_page_t* bpage;
const ib_rbt_node_t* rnode = NULL;
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list); UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list);
bpage = UT_LIST_GET_FIRST(buf_pool->flush_list); bpage = UT_LIST_GET_FIRST(buf_pool->flush_list);
/* If we are in recovery mode i.e.: flush_rbt != NULL
then each block in the flush_list must also be present
in the flush_rbt. */
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
rnode = rbt_first(buf_pool->flush_rbt);
}
while (bpage != NULL) { while (bpage != NULL) {
const ib_uint64_t om = bpage->oldest_modification; const ib_uint64_t om = bpage->oldest_modification;
ut_ad(bpage->in_flush_list); ut_ad(bpage->in_flush_list);
ut_a(buf_page_in_file(bpage)); ut_a(buf_page_in_file(bpage));
ut_a(om > 0); ut_a(om > 0);
/* If we are in recovery mode i.e.: flush_rbt != NULL
then each block in the flush_list must also be present
in the flush_rbt. */
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
ut_a(*rbt_value(buf_page_t*, ut_a(rnode);
rbt_lookup(buf_pool->flush_rbt, &bpage)) buf_page_t* rpage = *rbt_value(buf_page_t*,
== bpage); rnode);
ut_a(rpage);
ut_a(rpage == bpage);
rnode = rbt_next(buf_pool->flush_rbt, rnode);
} }
bpage = UT_LIST_GET_NEXT(list, bpage); bpage = UT_LIST_GET_NEXT(list, bpage);
...@@ -1452,6 +1524,10 @@ buf_flush_validate_low(void) ...@@ -1452,6 +1524,10 @@ buf_flush_validate_low(void)
ut_a(!bpage || om >= bpage->oldest_modification); ut_a(!bpage || om >= bpage->oldest_modification);
} }
/* By this time we must have exhausted the traversal of
flush_rbt (if active) as well. */
ut_a(rnode == NULL);
return(TRUE); return(TRUE);
} }
......
...@@ -1461,26 +1461,8 @@ buf_LRU_free_block( ...@@ -1461,26 +1461,8 @@ buf_LRU_free_block(
if (b->state == BUF_BLOCK_ZIP_PAGE) { if (b->state == BUF_BLOCK_ZIP_PAGE) {
buf_LRU_insert_zip_clean(b); buf_LRU_insert_zip_clean(b);
} else { } else {
buf_page_t* prev; /* Relocate on buf_pool->flush_list. */
buf_flush_relocate_on_flush_list(bpage, b);
ut_ad(b->in_flush_list);
ut_d(bpage->in_flush_list = FALSE);
prev = UT_LIST_GET_PREV(list, b);
UT_LIST_REMOVE(list, buf_pool->flush_list, b);
if (prev) {
ut_ad(prev->in_flush_list);
UT_LIST_INSERT_AFTER(
list,
buf_pool->flush_list,
prev, b);
} else {
UT_LIST_ADD_FIRST(
list,
buf_pool->flush_list,
b);
}
} }
bpage->zip.data = NULL; bpage->zip.data = NULL;
......
...@@ -28,6 +28,16 @@ void ...@@ -28,6 +28,16 @@ void
buf_flush_remove( buf_flush_remove(
/*=============*/ /*=============*/
buf_page_t* bpage); /* in: pointer to the block in question */ buf_page_t* bpage); /* in: pointer to the block in question */
/***********************************************************************
Relocates a buffer control block on the flush_list.
Note that it is assumed that the contents of bpage has already been
copied to dpage. */
UNIV_INTERN
void
buf_flush_relocate_on_flush_list(
/*=============================*/
buf_page_t* bpage, /* in/out: control block being moved */
buf_page_t* dpage); /* in/out: destination block */
/************************************************************************ /************************************************************************
Updates the flush system data structures when a write is completed. */ Updates the flush system data structures when a write is completed. */
UNIV_INTERN UNIV_INTERN
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment