Skip to content

Commit db87655

Browse files
committed
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 03a9366 commit db87655

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
@@ -685,6 +685,7 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
685685
mtr_t mtr;
686686
mtr.start();
687687
mtr.x_lock_space(&space);
688+
const auto space_id= space.id;
688689

689690
/* Lock all modified pages of the tablespace.
690691
@@ -694,55 +695,56 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
694695
mini-transaction commit and the server was killed, then
695696
discarding the to-be-trimmed pages without flushing would
696697
break crash recovery. */
698+
rescan:
697699
mysql_mutex_lock(&buf_pool.flush_list_mutex);
698-
699700
for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; )
700701
{
701702
ut_ad(bpage->oldest_modification());
702703
ut_ad(bpage->in_file());
703704

704705
buf_page_t *prev= UT_LIST_GET_PREV(list, bpage);
705706

706-
if (bpage->id().space() == space.id &&
707-
bpage->oldest_modification() != 1)
707+
if (bpage->oldest_modification() > 2 && bpage->id().space() == space_id)
708708
{
709709
ut_ad(bpage->frame);
710-
auto block= reinterpret_cast<buf_block_t*>(bpage);
711-
if (!bpage->lock.x_lock_try())
710+
bpage->fix();
712711
{
713-
rescan:
714-
/* Let buf_pool_t::release_freed_page() proceed. */
712+
/* Try to acquire an exclusive latch while the cache line is
713+
fresh after fix(). */
714+
const bool got_lock{bpage->lock.x_lock_try()};
715+
buf_pool.flush_hp.set(prev);
715716
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
716-
mysql_mutex_lock(&buf_pool.mutex);
717-
mysql_mutex_lock(&buf_pool.flush_list_mutex);
718-
mysql_mutex_unlock(&buf_pool.mutex);
719-
bpage= UT_LIST_GET_LAST(buf_pool.flush_list);
720-
continue;
717+
if (!got_lock)
718+
bpage->lock.x_lock();
721719
}
722-
buf_pool.flush_hp.set(prev);
723-
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
724720

725721
#ifdef BTR_CUR_HASH_ADAPT
726-
ut_ad(!block->index); /* There is no AHI on undo tablespaces. */
722+
/* There is no AHI on undo tablespaces. */
723+
ut_ad(!reinterpret_cast<buf_block_t*>(bpage)->index);
727724
#endif
728-
bpage->fix();
729725
ut_ad(!bpage->is_io_fixed());
730-
mysql_mutex_lock(&buf_pool.flush_list_mutex);
726+
ut_ad(bpage->id().space() == space_id);
731727

732-
if (bpage->oldest_modification() > 1)
728+
if (bpage->oldest_modification() > 2)
733729
{
730+
mtr.memo_push(reinterpret_cast<buf_block_t*>(bpage),
731+
MTR_MEMO_PAGE_X_FIX);
732+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
733+
ut_ad(bpage->oldest_modification() > 2);
734734
bpage->reset_oldest_modification();
735-
mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
736735
}
737736
else
738737
{
739738
bpage->unfix();
740739
bpage->lock.x_unlock();
740+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
741741
}
742742

743743
if (prev != buf_pool.flush_hp.get())
744-
/* Rescan, because we may have lost the position. */
744+
{
745+
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
745746
goto rescan;
747+
}
746748
}
747749

748750
bpage= prev;

0 commit comments

Comments
 (0)