Skip to content

Commit 318012a

Browse files
dr-mvuvova
authored andcommitted
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 0de3be8 (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
1 parent b735ca4 commit 318012a

File tree

4 files changed

+49
-30
lines changed

4 files changed

+49
-30
lines changed

storage/innobase/include/trx0sys.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ class trx_sys_t
10551055
void close();
10561056

10571057
/** @return total number of active (non-prepared) transactions */
1058-
ulint any_active_transactions();
1058+
size_t any_active_transactions(size_t *prepared= nullptr);
10591059

10601060

10611061
/**

storage/innobase/srv/srv0srv.cc

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,7 @@ void srv_master_callback(void*)
16971697
}
16981698

16991699
/** @return whether purge should exit due to shutdown */
1700-
static bool srv_purge_should_exit()
1700+
static bool srv_purge_should_exit(size_t old_history_size)
17011701
{
17021702
ut_ad(srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP);
17031703

@@ -1708,7 +1708,12 @@ static bool srv_purge_should_exit()
17081708
return true;
17091709

17101710
/* Slow shutdown was requested. */
1711-
if (const size_t history_size= trx_sys.rseg_history_len)
1711+
size_t prepared, active= trx_sys.any_active_transactions(&prepared);
1712+
const size_t history_size= trx_sys.rseg_history_len;
1713+
1714+
if (!history_size);
1715+
else if (!active && history_size == old_history_size && prepared);
1716+
else
17121717
{
17131718
static time_t progress_time;
17141719
time_t now= time(NULL);
@@ -1725,7 +1730,7 @@ static bool srv_purge_should_exit()
17251730
return false;
17261731
}
17271732

1728-
return !trx_sys.any_active_transactions();
1733+
return !active;
17291734
}
17301735

17311736
/*********************************************************************//**
@@ -1845,7 +1850,7 @@ static size_t srv_do_purge(ulint* n_total_purged)
18451850

18461851
*n_total_purged += n_pages_purged;
18471852
} while (n_pages_purged > 0 && !purge_sys.paused()
1848-
&& !srv_purge_should_exit());
1853+
&& !srv_purge_should_exit(rseg_history_len));
18491854

18501855
return(rseg_history_len);
18511856
}
@@ -1960,7 +1965,7 @@ static void purge_coordinator_callback_low()
19601965
}
19611966
}
19621967
while ((purge_sys.enabled() && !purge_sys.paused()) ||
1963-
!srv_purge_should_exit());
1968+
!srv_purge_should_exit(trx_sys.rseg_history_len));
19641969
}
19651970

19661971
static void purge_coordinator_callback(void*)
@@ -2031,15 +2036,19 @@ ulint srv_get_task_queue_length()
20312036
/** Shut down the purge threads. */
20322037
void srv_purge_shutdown()
20332038
{
2034-
if (purge_sys.enabled()) {
2035-
if (!srv_fast_shutdown && !opt_bootstrap)
2036-
srv_update_purge_thread_count(innodb_purge_threads_MAX);
2037-
while(!srv_purge_should_exit()) {
2038-
ut_a(!purge_sys.paused());
2039-
srv_wake_purge_thread_if_not_active();
2040-
purge_coordinator_task.wait();
2041-
}
2042-
purge_sys.coordinator_shutdown();
2043-
srv_shutdown_purge_tasks();
2044-
}
2039+
if (purge_sys.enabled())
2040+
{
2041+
if (!srv_fast_shutdown && !opt_bootstrap)
2042+
srv_update_purge_thread_count(innodb_purge_threads_MAX);
2043+
size_t history_size= trx_sys.rseg_history_len;
2044+
while (!srv_purge_should_exit(history_size))
2045+
{
2046+
history_size= trx_sys.rseg_history_len;
2047+
ut_a(!purge_sys.paused());
2048+
srv_wake_purge_thread_if_not_active();
2049+
purge_coordinator_task.wait();
2050+
}
2051+
purge_sys.coordinator_shutdown();
2052+
srv_shutdown_purge_tasks();
2053+
}
20452054
}

storage/innobase/trx/trx0purge.cc

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,7 @@ trx_purge_truncate_rseg_history(
448448
prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset
449449
- TRX_UNDO_HISTORY_NODE);
450450

451-
if (!rseg.trx_ref_count
452-
&& rseg.needs_purge <= (purge_sys.head.trx_no
453-
? purge_sys.head.trx_no
454-
: purge_sys.tail.trx_no)
455-
&& mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
456-
+ block->frame)
451+
if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + block->frame)
457452
== TRX_UNDO_TO_PURGE
458453
&& !mach_read_from_2(block->frame + hdr_addr.boffset
459454
+ TRX_UNDO_NEXT_LOG)) {
@@ -544,7 +539,8 @@ static void trx_purge_truncate_history()
544539
ut_ad(rseg->id == i);
545540
ut_ad(rseg->is_persistent());
546541
mutex_enter(&rseg->mutex);
547-
trx_purge_truncate_rseg_history(*rseg, head);
542+
if (!rseg->trx_ref_count && rseg->needs_purge <= head.trx_no)
543+
trx_purge_truncate_rseg_history(*rseg, head);
548544
mutex_exit(&rseg->mutex);
549545
}
550546
}

storage/innobase/trx/trx0sys.cc

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,15 +325,29 @@ trx_sys_t::close()
325325
}
326326

327327
/** @return total number of active (non-prepared) transactions */
328-
ulint trx_sys_t::any_active_transactions()
328+
size_t trx_sys_t::any_active_transactions(size_t *prepared)
329329
{
330-
uint32_t total_trx= 0;
331-
332-
trx_sys.trx_list.for_each([&total_trx](const trx_t &trx) {
333-
if (trx.state == TRX_STATE_COMMITTED_IN_MEMORY ||
334-
(trx.state == TRX_STATE_ACTIVE && trx.id))
330+
size_t total_trx= 0, prepared_trx= 0;
331+
332+
trx_sys.trx_list.for_each([&](const trx_t &trx) {
333+
switch (trx.state) {
334+
case TRX_STATE_NOT_STARTED:
335+
break;
336+
case TRX_STATE_ACTIVE:
337+
if (!trx.id)
338+
break;
339+
/* fall through */
340+
case TRX_STATE_COMMITTED_IN_MEMORY:
335341
total_trx++;
342+
break;
343+
case TRX_STATE_PREPARED:
344+
case TRX_STATE_PREPARED_RECOVERED:
345+
prepared_trx++;
346+
}
336347
});
337348

349+
if (prepared)
350+
*prepared= prepared_trx;
351+
338352
return total_trx;
339353
}

0 commit comments

Comments
 (0)