Skip to content

MDEV-40144 InnoDB: Add instant rollback#5272

Open
annbaek wants to merge 1 commit into
MariaDB:mainfrom
annbaek:feature_instant_rollback
Open

MDEV-40144 InnoDB: Add instant rollback#5272
annbaek wants to merge 1 commit into
MariaDB:mainfrom
annbaek:feature_instant_rollback

Conversation

@annbaek

@annbaek annbaek commented Jun 24, 2026

Copy link
Copy Markdown

Large transactions may spend a long time rolling back after crash recovery. During that time the server keeps rollback state and record locks for work that is only needed to make the old transaction effects disappear.

Add an instant rollback mode for InnoDB transactions whose undo record count reaches the configured threshold. When enabled, InnoDB can release record locks for the transaction and let individual row access handle the remaining undo state instead of running the full recovered transaction rollback immediately.

This introduces innodb_instant_rollback_enabled and innodb_instant_rollback_threshold, tracks instant rollback state in trx_t, and adds helper logic for recovered and normal rollback paths. The row undo and lock code are extended to collect and release temporary IRB record locks while preserving the existing rollback flow for transactions that do not qualify.

Add innodb.feature_instant_rollback to cover the crash recovery case with instant rollback enabled.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the Instant Rollback (IRB) feature for InnoDB, which includes new system variables, lock release mechanisms, and integration into the transaction rollback and crash recovery paths. The review feedback highlights several critical and high-severity issues: a potential infinite loop/hang in lock_release_record_locks_from_list when processing 1000 or more table locks, performance overhead from heap-allocating irb_row_t in row_undo, excessive warning logs for transactions that do not qualify for instant rollback, and an inappropriate error log level during crash recovery when the threshold is not met.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread storage/innobase/lock/lock0lock.cc Outdated
Comment thread storage/innobase/row/row0undo.cc
Comment thread storage/innobase/trx/trx0undo.cc
Comment thread storage/innobase/trx/trx0undo.cc Outdated
@annbaek annbaek force-pushed the feature_instant_rollback branch from 1d6215f to 9944864 Compare June 24, 2026 09:51
@annbaek

annbaek commented Jun 24, 2026

Copy link
Copy Markdown
Author

Addressed in the latest revision:

  • limited IRB lock release to the initial list length
  • avoided per-row heap allocation/new-delete overhead
  • downgraded threshold messages to debug/info
  • checked for hidden Unicode characters

@annbaek annbaek force-pushed the feature_instant_rollback branch 2 times, most recently from cfe7db2 to a45ad39 Compare June 24, 2026 13:14
@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Jun 25, 2026
@gkodinov gkodinov self-assigned this Jun 25, 2026

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution. This is a preliminary review.

The PR is formally correct, hence I'm approving it.
However there's 2 things to look at:

  • make sure the mariabackup.apply-log-only-incr failure is not related. It's the first time I'm seeing this happening.
  • keep a single commit per "feature". In your case you have the perfectly formatted commit and then a merge commit. If you want to (re-)merge the origin branch please use "rebase" in the github UI.

Please stand by for the final review.

@gkodinov gkodinov assigned Thirunarayanan and unassigned gkodinov Jun 25, 2026
@knielsen

Copy link
Copy Markdown
Member

Hi annbaek / shimengchu,

This is an interesting idea. Both the idea to release locks early during
rollback and handle required actions in the individual row access as needed;
and if this can be done in a patch as relatively simple as this one.

I don't quite understand how the patch works though.

What I see is that in row_undo(), it accumulates in the irb_row_t context
the list of locks encountered during row_undo_ins() / row_undo_mod(),
instead of in the trx->lock.trx_locks. And then the locks are released
immediately as part of processing that particular undo log record.

So does this mean that only new record locks created during undo processing
are affected, not record locks already held by the transaction to be rolled
back? So that rollback of the individual transaction proceeds as normal, but
with locks taken as part of undo processing held for a shorter amount of
time?

Or do any existing record locks of the transaction-to-be-rolled-back get
transferred to the list in irb_row_t during the rollback and get released
early this way?

Basically, my question is how the order of the different steps of rollback
processing are changed. Which locks exactly are released earlier, and when
are they released now relative to the other processing? And which part of
the undo processing now happen in a different thread than the one doing the
main rollback (if any)?

Another question, these parts of the patch appear to do nothing:

+  roll_ptr_t next_roll_ptr= 0;

--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -114,6 +114,10 @@ row_undo_ins_remove_clust_rec(
 	ut_ad(rec_is_metadata(rec, index->table->not_redundant())
 	      == (node->rec_type == TRX_UNDO_INSERT_METADATA));
 
+	if (irb_row) {
+		irb_row->save_recs_info(btr_pcur_get_btr_cur(&node->pcur));
+	}
+
 	switch (node->table->id) {
 	case DICT_COLUMNS_ID:
 		/* This is rolling back an INSERT into SYS_COLUMNS.
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index cd30090d437..cea9e315346 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -96,6 +96,10 @@ row_undo_mod_clust_low(
 		return DB_CORRUPTION;
 	}
 
+	if (irb_row) {
+		irb_row->save_recs_info(btr_cur);
+	}
+
 	ut_ad(rec_get_trx_id(btr_cur_get_rec(btr_cur),
 			     btr_cur_get_index(btr_cur))
 	      == thr_get_trx(thr)->id
@@ -1231,6 +1235,10 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked)
 	ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
 					       &info_bits);
 
+	if (irb_row) {
+		irb_row->next_roll_ptr = roll_ptr;
+	}
+
 	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
 				       node->heap);
 
+void irb_row_t::save_recs_info(btr_cur_t*)
+{
+}

+  next_roll_ptr= 0;

The save_recs_info() function is called but does nothing, and the
next_roll_ptr is set but never used. What was the intention of this part of
the patch?

  • Kristian.

@gkodinov gkodinov requested a review from Thirunarayanan June 25, 2026 08:05
@annbaek annbaek force-pushed the feature_instant_rollback branch 2 times, most recently from 1211ca8 to 5036436 Compare June 25, 2026 08:25
Large transactions may spend a long time rolling back, either during crash recovery or after an explicit ROLLBACK. During that time the server can keep record locks for work that is only needed while the rollback thread is applying undo records.

Add an instant rollback mode for InnoDB transactions whose undo record count reaches the configured threshold. When enabled, InnoDB releases the transaction's existing record locks before full rollback continues. The rollback still runs in the original rollback thread, and row undo collects any temporary IRB record locks in a per-row context so they can be released after each undo record.

This introduces innodb_instant_rollback_enabled and innodb_instant_rollback_threshold, tracks instant rollback state in trx_t, and handles both recovered transactions and normal explicit rollback. Transactions that do not qualify keep the existing rollback flow.

Add innodb.feature_instant_rollback coverage for both crash recovery and explicit ROLLBACK.
@annbaek annbaek force-pushed the feature_instant_rollback branch from 5036436 to 0afd3fd Compare June 25, 2026 08:41
@annbaek

annbaek commented Jun 25, 2026

Copy link
Copy Markdown
Author

Thank you for your contribution. This is a preliminary review.

The PR is formally correct, hence I'm approving it. However there's 2 things to look at:

  • make sure the mariabackup.apply-log-only-incr failure is not related. It's the first time I'm seeing this happening.
  • keep a single commit per "feature". In your case you have the perfectly formatted commit and then a merge commit. If you want to (re-)merge the origin branch please use "rebase" in the github UI.

Please stand by for the final review.

Thanks for the preliminary review.

I rebased the branch on the latest main and force-pushed it as a single feature commit. The merge commit has been removed.

I also added coverage for the explicit ROLLBACK case and re-ran the targeted tests locally:

  • innodb.feature_instant_rollback
  • sys_vars.sysvars_innodb
  • main.ps_3innodb

All passed locally. I do not see this change touching the mariabackup.apply-log-only-incr path directly, but I will check again if CI still reproduces a related failure.

@annbaek

annbaek commented Jun 25, 2026

Copy link
Copy Markdown
Author

Hi annbaek / shimengchu,

This is an interesting idea. Both the idea to release locks early during rollback and handle required actions in the individual row access as needed; and if this can be done in a patch as relatively simple as this one.

I don't quite understand how the patch works though.

What I see is that in row_undo(), it accumulates in the irb_row_t context the list of locks encountered during row_undo_ins() / row_undo_mod(), instead of in the trx->lock.trx_locks. And then the locks are released immediately as part of processing that particular undo log record.

So does this mean that only new record locks created during undo processing are affected, not record locks already held by the transaction to be rolled back? So that rollback of the individual transaction proceeds as normal, but with locks taken as part of undo processing held for a shorter amount of time?

Or do any existing record locks of the transaction-to-be-rolled-back get transferred to the list in irb_row_t during the rollback and get released early this way?

Basically, my question is how the order of the different steps of rollback processing are changed. Which locks exactly are released earlier, and when are they released now relative to the other processing? And which part of the undo processing now happen in a different thread than the one doing the main rollback (if any)?

Another question, these parts of the patch appear to do nothing:

+  roll_ptr_t next_roll_ptr= 0;

--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -114,6 +114,10 @@ row_undo_ins_remove_clust_rec(
 	ut_ad(rec_is_metadata(rec, index->table->not_redundant())
 	      == (node->rec_type == TRX_UNDO_INSERT_METADATA));
 
+	if (irb_row) {
+		irb_row->save_recs_info(btr_pcur_get_btr_cur(&node->pcur));
+	}
+
 	switch (node->table->id) {
 	case DICT_COLUMNS_ID:
 		/* This is rolling back an INSERT into SYS_COLUMNS.
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index cd30090d437..cea9e315346 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -96,6 +96,10 @@ row_undo_mod_clust_low(
 		return DB_CORRUPTION;
 	}
 
+	if (irb_row) {
+		irb_row->save_recs_info(btr_cur);
+	}
+
 	ut_ad(rec_get_trx_id(btr_cur_get_rec(btr_cur),
 			     btr_cur_get_index(btr_cur))
 	      == thr_get_trx(thr)->id
@@ -1231,6 +1235,10 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked)
 	ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
 					       &info_bits);
 
+	if (irb_row) {
+		irb_row->next_roll_ptr = roll_ptr;
+	}
+
 	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
 				       node->heap);
 
+void irb_row_t::save_recs_info(btr_cur_t*)
+{
+}

+  next_roll_ptr= 0;

The save_recs_info() function is called but does nothing, and the next_roll_ptr is set but never used. What was the intention of this part of the patch?

  • Kristian.

Thanks for the detailed questions.

The empty helpers were leftovers from an earlier two-phase plan. I removed them to avoid suggesting behavior that was not implemented.

The implemented IRB behavior now covers both recovered transactions and explicit ROLLBACK:

  • For explicit ROLLBACK, the rollback graph is started first. Then consider_instant_rollback_normal_trxs() checks the threshold, releases the transaction's existing record locks, and marks trx->instant_rollback_enabled.
  • For recovered transactions, the recovered undo count is checked first, and qualifying recovered transactions are marked for IRB when rollback reaches row undo.
  • The actual undo work still runs in the original rollback thread. No undo processing is moved to another thread.
  • During row undo, any temporary record locks needed by undo processing are collected in the thread-local irb_row_t list instead of trx->lock.trx_locks, and are released immediately after that undo record.
  • Table locks are not released through the IRB row-lock list.

I also added a test for explicit ROLLBACK. It pauses the rollback thread after row undo starts, then verifies that another transaction can update a record previously locked by the rolling-back transaction. This covers the early release of existing
record locks for explicit rollback.

@annbaek annbaek changed the title MDEV-40144 InnoDB: Add instant rollback for recovered transactions MDEV-40144 InnoDB: Add instant rollback Jun 25, 2026
@knielsen

knielsen commented Jun 25, 2026 via email

Copy link
Copy Markdown
Member

@Thirunarayanan Thirunarayanan requested a review from iMineLink June 25, 2026 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

4 participants