Skip to content

Commit e89bd39

Browse files
dr-mvuvova
authored andcommitted
MDEV-31343 Another server hang with innodb_undo_log_truncate=ON
trx_purge_truncate_history(): While waiting for a write-fixed block to become available, simply wait for an exclusive latch on it. Also, simplify the iteration: first check for oldest_modification>2 (to ignore clean pages or pages belonging to the temporary tablespace) and then compare the tablespace identifier. Before releasing buf_pool.flush_list_mutex we will buffer-fix the block of interest. In that way, buf_page_t::can_relocate() will not hold on the block and it must remain in the buffer pool until we have acquired an exclusive latch on it. If the block is still dirty, we will register it with the tablespace truncation mini-transaction; else, we will simply release the latch and buffer-fix and move to the next block. This also reverts commit c4d7939 because that fix should no longer be necessary; the wait for an exclusive block latch should allow buf_pool_t::release_freed_page() on the same block to proceed. Tested by: Axel Schwenke, Matthias Leich
1 parent a24f2bb commit e89bd39

File tree

1 file changed

+22
-20
lines changed

1 file changed

+22
-20
lines changed

storage/innobase/trx/trx0purge.cc

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
706706
mtr_t mtr;
707707
mtr.start();
708708
mtr.x_lock_space(&space);
709+
const auto space_id= space.id;
709710

710711
/* Lock all modified pages of the tablespace.
711712
@@ -715,55 +716,56 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
715716
mini-transaction commit and the server was killed, then
716717
discarding the to-be-trimmed pages without flushing would
717718
break crash recovery. */
719+
rescan:
718720
mysql_mutex_lock(&buf_pool.flush_list_mutex);
719-
720721
for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; )
721722
{
722723
ut_ad(bpage->oldest_modification());
723724
ut_ad(bpage->in_file());
724725

725726
buf_page_t *prev= UT_LIST_GET_PREV(list, bpage);
726727

727-
if (bpage->id().space() == space.id &&
728-
bpage->oldest_modification() != 1)
728+
if (bpage->oldest_modification() > 2 && bpage->id().space() == space_id)
729729
{
730730
ut_ad(bpage->frame);
731-
auto block= reinterpret_cast<buf_block_t*>(bpage);
732-
if (!bpage->lock.x_lock_try())
731+
bpage->fix();
733732
{
734-
rescan:
735-
/* Let buf_pool_t::release_freed_page() proceed. */
733+
/* Try to acquire an exclusive latch while the cache line is
734+
fresh after fix(). */
735+
const bool got_lock{bpage->lock.x_lock_try()};
736+
buf_pool.flush_hp.set(prev);
736737
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
737-
mysql_mutex_lock(&buf_pool.mutex);
738-
mysql_mutex_lock(&buf_pool.flush_list_mutex);
739-
mysql_mutex_unlock(&buf_pool.mutex);
740-
bpage= UT_LIST_GET_LAST(buf_pool.flush_list);
741-
continue;
738+
if (!got_lock)
739+
bpage->lock.x_lock();
742740
}
743-
buf_pool.flush_hp.set(prev);
744-
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
745741

746742
#ifdef BTR_CUR_HASH_ADAPT
747-
ut_ad(!block->index); /* There is no AHI on undo tablespaces. */
743+
/* There is no AHI on undo tablespaces. */
744+
ut_ad(!reinterpret_cast<buf_block_t*>(bpage)->index);
748745
#endif
749-
bpage->fix();
750746
ut_ad(!bpage->is_io_fixed());
751-
mysql_mutex_lock(&buf_pool.flush_list_mutex);
747+
ut_ad(bpage->id().space() == space_id);
752748

753-
if (bpage->oldest_modification() > 1)
749+
if (bpage->oldest_modification() > 2)
754750
{
751+
mtr.memo_push(reinterpret_cast<buf_block_t*>(bpage),
752+
MTR_MEMO_PAGE_X_FIX);
753+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
754+
ut_ad(bpage->oldest_modification() > 2);
755755
bpage->reset_oldest_modification();
756-
mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
757756
}
758757
else
759758
{
760759
bpage->unfix();
761760
bpage->lock.x_unlock();
761+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
762762
}
763763

764764
if (prev != buf_pool.flush_hp.get())
765-
/* Rescan, because we may have lost the position. */
765+
{
766+
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
766767
goto rescan;
768+
}
767769
}
768770

769771
bpage= prev;

0 commit comments

Comments
 (0)