Commit 2db5f1b2 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-32049 Deadlock due to log_free_check() in trx_purge_truncate_history()

The function log_free_check() is not supposed to be invoked while
the caller is holding any InnoDB synchronization objects, such as
buffer page latches, tablespace latches, index tree latches, or
in this case, rseg->mutex (rseg->latch in 10.6 or later).

A hang was reported in 10.6 where several threads were waiting for
an rseg->latch that had been exclusively acquired in
trx_purge_truncate_history(), which invoked log_free_check() inside
trx_purge_truncate_rseg_history(). Because the threads that were
waiting for the rseg->latch were holding exclusive latches on some
index pages, log_free_check() was unable to advance the checkpoint
because those index pages could not be written out.

trx_purge_truncate_history(): Invoke log_free_check() before
acquiring the rseg->mutex and invoking trx_purge_free_segment().

trx_purge_free_segment(): Do not invoke log_free_check() in order
to avoid a deadlock.
parent 3c86765e
......@@ -346,7 +346,6 @@ static
void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr)
{
mtr.commit();
log_free_check();
mtr.start();
ut_ad(mutex_own(&rseg->mutex));
......@@ -376,7 +375,6 @@ void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr)
This does not matter when using multiple innodb_undo_tablespaces;
innodb_undo_log_truncate=ON will be able to reclaim the space. */
log_free_check();
mtr.start();
ut_ad(rw_lock_s_lock_nowait(block->debug_latch, __FILE__, __LINE__));
rw_lock_x_lock(&block->lock);
......@@ -545,6 +543,7 @@ void trx_purge_truncate_history()
{
ut_ad(rseg->id == i);
ut_ad(rseg->is_persistent());
log_free_check();
mutex_enter(&rseg->mutex);
trx_purge_truncate_rseg_history(*rseg, head,
!rseg->trx_ref_count &&
......
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