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
--error ER_UNKNOWN_STORAGE_ENGINE
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
SELECT * FROM t1 WHERE PK = 1;
--error ER_NOT_KEYFILE
......
......@@ -2653,7 +2653,6 @@ buf_page_get_low(
}
} else {
buf_read_ahead_random(page_id, zip_size, ibuf_inside(mtr));
retries = 0;
}
ut_d(if (!(++buf_dbg_counter % 5771)) buf_pool.validate());
......@@ -2672,15 +2671,45 @@ buf_page_get_low(
return nullptr;
}
if (UNIV_LIKELY(block->page.frame != nullptr)) {
/* A read-fix is released after block->page.lock
in buf_page_t::read_complete() or
buf_pool_t::corrupted_evict(), or
after buf_zip_decompress() in this function. */
block->page.lock.s_lock();
state = block->page.state();
block->page.lock.s_unlock();
ut_ad(state < buf_page_t::READ_FIX);
/* A read-fix is released after block->page.lock
in buf_page_t::read_complete() or
buf_pool_t::corrupted_evict(), or
after buf_zip_decompress() in this function. */
block->page.lock.s_lock();
state = block->page.state();
ut_ad(state < buf_page_t::READ_FIX);
const page_id_t id{block->page.id()};
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) {
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