mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
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 aaef2e1d8c
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.
This commit is contained in:
parent
80fff4c6b1
commit
35d477dd1d
2 changed files with 42 additions and 3 deletions
|
@ -1,4 +1,5 @@
|
|||
--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 @@ retry:
|
|||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue