Skip to content

Commit 6c09a65

Browse files
committed
MDEV-14985 innodb_undo_log_truncate may be blocked if transactions were recovered at startup
The field trx_rseg_t::trx_ref_count that was added in WL#6965 in MySQL 5.7.5 is being incremented twice if a recovered transaction includes both undo log partitions insert_undo and update_undo. This reference count is being used in trx_purge(), which invokes trx_purge_initiate_truncate() to try to truncate an undo tablespace file. Because of the double-increment, the trx_ref_count would never reach 0. It is possible that after the failed truncation attempt, the undo tablespace would be disabled for logging any new transactions until the server is restarted (hopefully after committing or rolling back all transactions, so that no transactions would be recovered on the next startup). trx_resurrect_insert(), trx_resurrect_update(): Do not increment trx_ref_count. Instead, let the caller do that. trx_lists_init_at_db_start(): Increment rseg->trx_ref_count only once for each recovered transaction. Adjust comments. Finally, if innodb_force_recovery prevents the undo log scan, do not bother iterating the empty lists.
1 parent cc915cd commit 6c09a65

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

storage/innobase/trx/trx0trx.cc

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -824,10 +824,6 @@ trx_resurrect_insert(
824824
ut_d(trx->start_line = __LINE__);
825825

826826
trx->rsegs.m_redo.rseg = rseg;
827-
/* For transactions with active data will not have rseg size = 1
828-
or will not qualify for purge limit criteria. So it is safe to increment
829-
this trx_ref_count w/o mutex protection. */
830-
++trx->rsegs.m_redo.rseg->trx_ref_count;
831827
*trx->xid = undo->xid;
832828
trx->id = undo->trx_id;
833829
trx->rsegs.m_redo.insert_undo = undo;
@@ -934,10 +930,6 @@ trx_resurrect_update(
934930
trx_rseg_t* rseg) /*!< in/out: rollback segment */
935931
{
936932
trx->rsegs.m_redo.rseg = rseg;
937-
/* For transactions with active data will not have rseg size = 1
938-
or will not qualify for purge limit criteria. So it is safe to increment
939-
this trx_ref_count w/o mutex protection. */
940-
++trx->rsegs.m_redo.rseg->trx_ref_count;
941933
*trx->xid = undo->xid;
942934
trx->id = undo->trx_id;
943935
trx->rsegs.m_redo.update_undo = undo;
@@ -991,19 +983,22 @@ trx_lists_init_at_db_start()
991983

992984
purge_sys = UT_NEW_NOKEY(purge_sys_t());
993985

994-
if (srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
995-
trx_rseg_array_init();
986+
if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
987+
return;
996988
}
997989

990+
trx_rseg_array_init();
991+
998992
/* Look from the rollback segments if there exist undo logs for
999993
transactions. */
1000994

1001995
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
1002996
trx_undo_t* undo;
1003997
trx_rseg_t* rseg = trx_sys->rseg_array[i];
1004998

1005-
/* At this stage non-redo rseg slots are all NULL as they are
1006-
re-created on server start and existing slots are not read. */
999+
/* Some rollback segment may be unavailable,
1000+
especially if the server was previously run with a
1001+
non-default value of innodb_undo_logs. */
10071002
if (rseg == NULL) {
10081003
continue;
10091004
}
@@ -1013,6 +1008,11 @@ trx_lists_init_at_db_start()
10131008
undo != NULL;
10141009
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
10151010

1011+
/* trx_purge() will not run before we return,
1012+
so we can safely increment this without
1013+
holding rseg->mutex. */
1014+
++rseg->trx_ref_count;
1015+
10161016
trx_t* trx;
10171017

10181018
trx = trx_resurrect_insert(undo, rseg);
@@ -1037,6 +1037,7 @@ trx_lists_init_at_db_start()
10371037

10381038
if (trx == NULL) {
10391039
trx = trx_allocate_for_background();
1040+
++rseg->trx_ref_count;
10401041

10411042
ut_d(trx->start_file = __FILE__);
10421043
ut_d(trx->start_line = __LINE__);

0 commit comments

Comments
 (0)