mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
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 0de3be8cfd (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.
Tested by: Matthias Leich
This commit is contained in:
committed by
Sergei Golubchik
parent
b735ca4773
commit
318012a80a
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
size_t total_trx= 0, prepared_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))
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user