Commit 82f5981e authored by Marko Mäkelä's avatar Marko Mäkelä Committed by Oleksandr Byelkin

MDEV-27058 fixup: Crash in innodb.leaf_page_corrupted_during_recovery

buf_page_get_low(): If the page was read-fixed, validate the page ID
because the page could have been marked as corrupted. We should retry
the page read in this case, instead of returning a soon-to-be-evicted
corrupted page to the caller.

This was initially only observed on Microsoft Windows.
On Linux, this was repeated after adding a sleep
to buf_pool_t::corrupted_evict() between
bpage->zip.fix.fetch_sub() and bpage->lock.x_unlock().
parent 05c33d62
...@@ -47,7 +47,8 @@ EOF ...@@ -47,7 +47,8 @@ EOF
--error ER_UNKNOWN_STORAGE_ENGINE --error ER_UNKNOWN_STORAGE_ENGINE
SELECT * FROM t1 WHERE PK = 1; SELECT * FROM t1 WHERE PK = 1;
let $restart_parameters=--innodb-force-recovery=1; # We will disable also purge, to not let it request the corrupted page.
let $restart_parameters=--innodb-force-recovery=2;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
SELECT * FROM t1 WHERE PK = 1; SELECT * FROM t1 WHERE PK = 1;
--error ER_NOT_KEYFILE --error ER_NOT_KEYFILE
......
...@@ -2653,7 +2653,6 @@ buf_page_get_low( ...@@ -2653,7 +2653,6 @@ buf_page_get_low(
} }
} else { } else {
buf_read_ahead_random(page_id, zip_size, ibuf_inside(mtr)); buf_read_ahead_random(page_id, zip_size, ibuf_inside(mtr));
retries = 0;
} }
ut_d(if (!(++buf_dbg_counter % 5771)) buf_pool.validate()); ut_d(if (!(++buf_dbg_counter % 5771)) buf_pool.validate());
...@@ -2672,15 +2671,45 @@ buf_page_get_low( ...@@ -2672,15 +2671,45 @@ buf_page_get_low(
return nullptr; return nullptr;
} }
if (UNIV_LIKELY(block->page.frame != nullptr)) { /* A read-fix is released after block->page.lock
/* A read-fix is released after block->page.lock in buf_page_t::read_complete() or
in buf_page_t::read_complete() or buf_pool_t::corrupted_evict(), or
buf_pool_t::corrupted_evict(), or after buf_zip_decompress() in this function. */
after buf_zip_decompress() in this function. */ block->page.lock.s_lock();
block->page.lock.s_lock(); state = block->page.state();
state = block->page.state(); ut_ad(state < buf_page_t::READ_FIX);
block->page.lock.s_unlock(); const page_id_t id{block->page.id()};
ut_ad(state < buf_page_t::READ_FIX); block->page.lock.s_unlock();
if (UNIV_UNLIKELY(id != page_id)) {
ut_ad(id == page_id_t{~0ULL});
block->page.unfix();
if (++retries < BUF_PAGE_READ_MAX_RETRIES) {
goto loop;
}
if (err) {
*err = DB_PAGE_CORRUPTED;
}
if (page_id.space() == TRX_SYS_SPACE) {
} else if (page_id.space() == SRV_TMP_SPACE_ID) {
} else if (fil_space_t* space =
fil_space_t::get(page_id.space())) {
bool set = dict_set_corrupted_by_space(space);
space->release();
if (set) {
return nullptr;
}
}
ib::fatal() << "Unable to read page " << page_id
<< " into the buffer pool after "
<< BUF_PAGE_READ_MAX_RETRIES
<< ". The most probable cause"
" of this error may be that the"
" table has been corrupted."
" See https://mariadb.com/kb/en/library/innodb-recovery-modes/";
} }
} else if (mode == BUF_PEEK_IF_IN_POOL) { } else if (mode == BUF_PEEK_IF_IN_POOL) {
if (UNIV_UNLIKELY(!block->page.frame)) { if (UNIV_UNLIKELY(!block->page.frame)) {
......
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