Leaving the savepoint in the transaction stack upon rollback is incorrect

Created on 8 December 2023, about 1 year ago
Updated 11 December 2023, about 1 year ago

Problem/Motivation

While working on 📌 [PP-1] Convert all transactions to explicit COMMIT Postponed , I realized the changes in 🐛 [PP-1] Rolling back to a savepoint should leave the savepoint in the transaction stack Postponed are incorrect.

Right now, you can't rollback a root transaction if you just rolled back a later savepoint. The later savepoint remains active both on the DB and on the TransactionManager stack, and trying to roll back the outer root transaction end in an out of sequence exception. This is because the savepoint is not released, just rolled back to.

However Drupal expects to start a transaction without caring whether it's a root or a savepoint; and to roll it back without knowing the stack state.

Proposed resolution

Upon rollback of a Transaction object, besides the DB savepoint to rollback, also do a DB savepoint release and void the item on the transaction stack.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Fixed

Version

10.2

Component
Database 

Last updated 2 days ago

  • Maintained by
  • 🇳🇱Netherlands @daffie
Created by

🇮🇹Italy mondrake 🇮🇹

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @mondrake
  • Issue was unassigned.
  • Status changed to Needs review about 1 year ago
  • Status changed to Needs work about 1 year ago
  • 🇮🇹Italy mondrake 🇮🇹

    Adding an additional test case, repeated rollback.

  • Status changed to Needs review about 1 year ago
  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    I'm a little confused by the idea that the changes in 🐛 [PP-1] Rolling back to a savepoint should leave the savepoint in the transaction stack Postponed were "partially incorrect". Doesn't this issue completely revert the nature of the changes made there?

    I think this fix is correct but I think that we should have a re-read of the docs that 🐛 [PP-1] Rolling back to a savepoint should leave the savepoint in the transaction stack Postponed was based on

    The ROLLBACK TO SAVEPOINT statement rolls back a transaction to the named savepoint without terminating the transaction. Modifications that the current transaction made to rows after the savepoint was set are undone in the rollback, but InnoDB does not release the row locks that were stored in memory after the savepoint. (For a new inserted row, the lock information is carried by the transaction ID stored in the row; the lock is not separately stored in memory. In this case, the row lock is released in the undo.) Savepoints that were set at a later time than the named savepoint are deleted.

    We specifically prevent Savepoints that were set at a later time than the named savepoint are deleted. from happening and we throw out of order errors. Are we sure the behaviour we've implemented here is correct. I'm happy to leave this unresolved here as I think this issue is returning us to the behaviour before all the recent transaction changes.

  • 🇮🇹Italy mondrake 🇮🇹

    Removed 'partially' from the IS.

    What we do here is revert the behaviour that the savepoint rolled back to was left alive, both on the DB and as an item on the TransactionManager stack. After this patch, we RELEASE SAVEPOINT the rolled back savepoint on the DB, and void the item on the TransactionManager so it cannot be committed or rolled back again.

    As far as I can remember, I was quite confused by Drupal logic - you could commit any savepoint/root at discretion, but you only could rollback LIFO, i.e. without breaking the order. However, I made efforts to keep this logic in the TransactionManager, too.

    On this basis,

    We specifically prevent Savepoints that were set at a later time than the named savepoint are deleted. from happening and we throw out of order errors. Are we sure the behaviour we've implemented here is correct.

    I think (hope) it's correct. It's implicit in the LIFO behavior. It's now covered by DriverSpecificTransactionTestBase::testRollbackSavepointWithLaterSavepoint.

    Happy to loosen the LIFO behaviour if I was mistaken, and allow rolling back to savepoint/root coming earlier than the last active, if that's the correct expected behavior. It was a grey zone for me, but I remember I found barriers in the previous testing that were indicating to me strict LIFO.

  • Status changed to RTBC about 1 year ago
  • 🇬🇧United Kingdom alexpott 🇪🇺🌍

    Let's do this fix as it is really important. I think we can think about loosening the LIFO behaviour in a future issue.

  • 🇮🇹Italy mondrake 🇮🇹

    Thanks. Filed 📌 Loosen TransactionManager LIFO behaviour on rollback Active as a follow-up.

    • catch committed 50c767e5 on 10.2.x
      Issue #3407080 by mondrake, alexpott: Leaving the savepoint in the...
    • catch committed 64f1c854 on 11.x
      Issue #3407080 by mondrake, alexpott: Leaving the savepoint in the...
  • Status changed to Fixed about 1 year ago
  • 🇬🇧United Kingdom catch

    Committed/pushed to 11.x and cherry-picked to 10.2.x, thanks!

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024