From d03a02ea989b7568675722435bb5ea41bcb19d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 17 May 2023 17:11:55 +0300 Subject: MDEV-31234 InnoDB does not free UNDO after the fix of MDEV-30671 trx_purge_truncate_history(): Only call trx_purge_truncate_rseg_history() if the rollback segment is safe to process. This will avoid leaking undo log pages that are not yet ready to be processed. This fixes a regression that was introduced in commit 0de3be8cfdfc26f5c236eaefe12d03c7b4af22c8 (MDEV-30671). trx_sys_t::any_active_transactions(): Separately count XA PREPARE transactions. srv_purge_should_exit(): Terminate slow shutdown if the history size does not change and XA PREPARE transactions exist in the system. This will avoid a hang of the test innodb.recovery_shutdown. --- storage/innobase/include/trx0sys.h | 2 +- storage/innobase/srv/srv0srv.cc | 41 +++++++++++++++++++++++--------------- storage/innobase/trx/trx0purge.cc | 10 +++------- storage/innobase/trx/trx0sys.cc | 26 ++++++++++++++++++------ 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index e033a3e1fe4..016ac0b1363 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1055,7 +1055,7 @@ public: void close(); /** @return total number of active (non-prepared) transactions */ - ulint any_active_transactions(); + size_t any_active_transactions(size_t *prepared= nullptr); /** diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 57aa4bef9fe..50569f810ea 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1697,7 +1697,7 @@ void srv_master_callback(void*) } /** @return whether purge should exit due to shutdown */ -static bool srv_purge_should_exit() +static bool srv_purge_should_exit(size_t old_history_size) { ut_ad(srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP); @@ -1708,7 +1708,12 @@ static bool srv_purge_should_exit() return true; /* Slow shutdown was requested. */ - if (const size_t history_size= trx_sys.rseg_history_len) + size_t prepared, active= trx_sys.any_active_transactions(&prepared); + const size_t history_size= trx_sys.rseg_history_len; + + if (!history_size); + else if (!active && history_size == old_history_size && prepared); + else { static time_t progress_time; time_t now= time(NULL); @@ -1725,7 +1730,7 @@ static bool srv_purge_should_exit() return false; } - return !trx_sys.any_active_transactions(); + return !active; } /*********************************************************************//** @@ -1845,7 +1850,7 @@ static size_t srv_do_purge(ulint* n_total_purged) *n_total_purged += n_pages_purged; } while (n_pages_purged > 0 && !purge_sys.paused() - && !srv_purge_should_exit()); + && !srv_purge_should_exit(rseg_history_len)); return(rseg_history_len); } @@ -1960,7 +1965,7 @@ static void purge_coordinator_callback_low() } } while ((purge_sys.enabled() && !purge_sys.paused()) || - !srv_purge_should_exit()); + !srv_purge_should_exit(trx_sys.rseg_history_len)); } static void purge_coordinator_callback(void*) @@ -2031,15 +2036,19 @@ ulint srv_get_task_queue_length() /** Shut down the purge threads. */ void srv_purge_shutdown() { - if (purge_sys.enabled()) { - if (!srv_fast_shutdown && !opt_bootstrap) - srv_update_purge_thread_count(innodb_purge_threads_MAX); - while(!srv_purge_should_exit()) { - ut_a(!purge_sys.paused()); - srv_wake_purge_thread_if_not_active(); - purge_coordinator_task.wait(); - } - purge_sys.coordinator_shutdown(); - srv_shutdown_purge_tasks(); - } + if (purge_sys.enabled()) + { + if (!srv_fast_shutdown && !opt_bootstrap) + srv_update_purge_thread_count(innodb_purge_threads_MAX); + size_t history_size= trx_sys.rseg_history_len; + while (!srv_purge_should_exit(history_size)) + { + history_size= trx_sys.rseg_history_len; + ut_a(!purge_sys.paused()); + srv_wake_purge_thread_if_not_active(); + purge_coordinator_task.wait(); + } + purge_sys.coordinator_shutdown(); + srv_shutdown_purge_tasks(); + } } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b22a85f4646..97979a3fefe 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -448,12 +448,7 @@ func_exit: prev_hdr_addr.boffset = static_cast(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - if (!rseg.trx_ref_count - && rseg.needs_purge <= (purge_sys.head.trx_no - ? purge_sys.head.trx_no - : purge_sys.tail.trx_no) - && mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE - + block->frame) + if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + block->frame) == TRX_UNDO_TO_PURGE && !mach_read_from_2(block->frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) { @@ -544,7 +539,8 @@ static void trx_purge_truncate_history() ut_ad(rseg->id == i); ut_ad(rseg->is_persistent()); mutex_enter(&rseg->mutex); - trx_purge_truncate_rseg_history(*rseg, head); + if (!rseg->trx_ref_count && rseg->needs_purge <= head.trx_no) + trx_purge_truncate_rseg_history(*rseg, head); mutex_exit(&rseg->mutex); } } diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index bcde969eb41..ab3de55db64 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -325,15 +325,29 @@ trx_sys_t::close() } /** @return total number of active (non-prepared) transactions */ -ulint trx_sys_t::any_active_transactions() +size_t trx_sys_t::any_active_transactions(size_t *prepared) { - uint32_t total_trx= 0; - - trx_sys.trx_list.for_each([&total_trx](const trx_t &trx) { - if (trx.state == TRX_STATE_COMMITTED_IN_MEMORY || - (trx.state == TRX_STATE_ACTIVE && trx.id)) + size_t total_trx= 0, prepared_trx= 0; + + trx_sys.trx_list.for_each([&](const trx_t &trx) { + switch (trx.state) { + case TRX_STATE_NOT_STARTED: + break; + case TRX_STATE_ACTIVE: + if (!trx.id) + break; + /* fall through */ + case TRX_STATE_COMMITTED_IN_MEMORY: total_trx++; + break; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + prepared_trx++; + } }); + if (prepared) + *prepared= prepared_trx; + return total_trx; } -- cgit v1.2.1