MDEV-34453 Trying to read 16384 bytes at 70368744161280 outside the bounds of the file: ./ibdata1

The issue is caused by a race between buf_page_create_low getting the
page from buffer pool hash and buf_LRU_free_page evicting it from LRU.

The issue is introduced in 10.6 by MDEV-27058
commit aaef2e1d
MDEV-27058: Reduce the size of buf_block_t and buf_page_t

The solution is buffer fix the page before releasing buffer pool mutex
in buf_page_create_low when x_lock_try fails to acquire the page latch.
parent 80fff4c6
--source include/no_valgrind_without_big.inc
--source include/maybe_debug.inc
######## t/ddl_innodb.test ######
#
# Stress the storage engine InnoDB with CREATE/DROP TABLE/INDEX
......@@ -34,6 +35,13 @@ if (!$run)
##### Some preparations needed for the ddl*.inc scripts
--source suite/stress/include/ddl.pre
if ($have_debug) {
--disable_query_log
SET @old_debug_dbug = @@global.debug_dbug;
SET DEBUG_DBUG="+d,ib_buf_create_intermittent_wait";
--enable_query_log
}
--source suite/stress/include/ddl1.inc
--source suite/stress/include/ddl2.inc
--source suite/stress/include/ddl3.inc
......@@ -43,5 +51,11 @@ if (!$run)
--source suite/stress/include/ddl7.inc
--source suite/stress/include/ddl8.inc
if ($have_debug) {
--disable_query_log
SET @@global.debug_dbug = @old_debug_dbug;
--enable_query_log
}
##### Cleanup
--source suite/stress/include/ddl.cln
......@@ -3289,22 +3289,47 @@ static buf_block_t *buf_page_create_low(page_id_t page_id, ulint zip_size,
if (!mtr->have_x_latch(reinterpret_cast<const buf_block_t&>(*bpage)))
{
const bool got= bpage->lock.x_lock_try();
if (!got)
/* Buffer-fix the block to prevent the block being concurrently freed
after we release the buffer pool mutex. It should work fine with
concurrent load of the page (free on disk) to buffer pool due to
possible read ahead. After we find a zero filled page during load, we
call buf_pool_t::corrupted_evict, where we try to wait for all buffer
fixes to go away only after resetting the page ID and releasing the
page latch. */
auto state= bpage->fix();
DBUG_EXECUTE_IF("ib_buf_create_intermittent_wait",
{
static bool need_to_wait = false;
need_to_wait = !need_to_wait;
/* Simulate try lock failure in every alternate call. */
if (need_to_wait) {
goto must_wait;
}
});
if (!bpage->lock.x_lock_try())
{
#ifndef DBUG_OFF
must_wait:
#endif
mysql_mutex_unlock(&buf_pool.mutex);
bpage->lock.x_lock();
const page_id_t id{bpage->id()};
if (UNIV_UNLIKELY(id != page_id))
{
ut_ad(id.is_corrupted());
ut_ad(bpage->is_freed());
bpage->unfix();
bpage->lock.x_unlock();
goto retry;
}
mysql_mutex_lock(&buf_pool.mutex);
state= bpage->state();
ut_ad(!bpage->is_io_fixed(state));
ut_ad(bpage->buf_fix_count(state));
}
auto state= bpage->fix();
ut_ad(state >= buf_page_t::FREED);
ut_ad(state < buf_page_t::READ_FIX);
......
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