summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2023-05-17 17:11:55 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2023-05-17 17:11:55 +0300
commitd03a02ea989b7568675722435bb5ea41bcb19d75 (patch)
tree06de2a1802935edb2cbead19c36b4940208e966c
parentc9eff1a144ba44846373660a30d342d3f0dc91a5 (diff)
downloadmariadb-git-bb-10.5-MDEV-31234.tar.gz
MDEV-31234 InnoDB does not free UNDO after the fix of MDEV-30671bb-10.5-MDEV-31234
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.
-rw-r--r--storage/innobase/include/trx0sys.h2
-rw-r--r--storage/innobase/srv/srv0srv.cc41
-rw-r--r--storage/innobase/trx/trx0purge.cc10
-rw-r--r--storage/innobase/trx/trx0sys.cc26
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<uint16_t>(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;
}