8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 06:43:04 +01:00

Ensure the txn-level savepoint is always destroyed (and re-created in the case of RETAIN)

This commit is contained in:
Dmitry Yemanov 2020-09-25 15:27:30 +03:00
parent 0b0a23f053
commit 3969544fe8

View File

@ -499,15 +499,16 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag
if (transaction->tra_flags & (TRA_prepare2 | TRA_reconnected))
MET_update_transaction(tdbb, transaction, true);
// Get rid of the rest of savepoints to allow intermediate garbage collection
// in indices and BLOBs after in-place updates
while (transaction->tra_save_point)
transaction->rollforwardSavepoint(tdbb);
// Flush pages if transaction logically modified data
if (transaction->tra_flags & TRA_write)
{
// Get rid of the rest of savepoints to allow intermediate garbage collection
// in indices and BLOBs after in-place updates
while (transaction->tra_save_point)
transaction->rollforwardSavepoint(tdbb);
transaction_flush(tdbb, FLUSH_TRAN, transaction->tra_number);
}
else if ((transaction->tra_flags & (TRA_prepare2 | TRA_reconnected)) ||
@ -1396,8 +1397,13 @@ void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl
while (transaction->tra_save_point && !transaction->tra_save_point->isRoot())
transaction->rollforwardSavepoint(tdbb);
if (transaction->tra_save_point) // we still can use undo log for rollback, it wasn't reset because of no_auto_undo flag or size
if (transaction->tra_save_point)
{
// We still can use the undo log for rollback, it wasn't reset because of
// no_auto_undo flag or being oversized
fb_assert(transaction->tra_save_point->isRoot());
// In an attempt to avoid deadlocks, clear the precedence by writing
// all dirty buffers for this transaction.
@ -1420,7 +1426,12 @@ void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl
// Prevent a bugcheck in TRA_set_state to cause a loop
// Clear the error because the rollback will succeed.
fb_utils::init_status(tdbb->tdbb_status_vector);
// If undo failed, free all savepoints
Savepoint::destroy(transaction->tra_save_point);
}
fb_assert(!transaction->tra_save_point);
}
else if (!(transaction->tra_flags & TRA_write))
{
@ -2545,6 +2556,9 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
// All savepoints must already be released in TRA_commit/TRA_rollback
fb_assert(!transaction->tra_save_point);
// The new transaction needs to remember the 'commit-retained' transaction
// because it must see the operations of the 'commit-retained' transaction and
// its snapshot doesn't contain these operations.
@ -2639,9 +2653,9 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i
transaction->tra_flags &= ~(TRA_write | TRA_prepared);
// All savepoint were already released in TRA_commit/TRA_rollback except, may be, empty transaction-level one
if (!transaction->tra_save_point && !(transaction->tra_flags & TRA_no_auto_undo))
transaction->startSavepoint(true); // start new savepoint if necessary
// Restart a transaction-level savepoint, unless NO AUTO UNDO is specified
if (!(transaction->tra_flags & TRA_no_auto_undo))
transaction->startSavepoint(true);
if (transaction->tra_flags & TRA_precommitted)
{