summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Russotto <matthew.russotto@10gen.com>2019-08-21 09:54:58 -0400
committerMatthew Russotto <matthew.russotto@10gen.com>2019-08-21 09:54:58 -0400
commitf661267bf981e3b315d7e942057ab0ac9dc90bef (patch)
tree24968a20050d47b9644dc64dfa0c7b542b01d90e /src
parentf5ee95fe7e9e6ca3db9db01e97a917f754d4d8cd (diff)
downloadmongo-f661267bf981e3b315d7e942057ab0ac9dc90bef.tar.gz
SERVER-41457 Unify the different ways the TransactionParticipant offers for aborting a transaction
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands/txn_cmds.cpp2
-rw-r--r--src/mongo/db/kill_sessions_local.cpp74
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp2
-rw-r--r--src/mongo/db/repl/transaction_oplog_application.cpp2
-rw-r--r--src/mongo/db/s/txn_two_phase_commit_cmds.cpp7
-rw-r--r--src/mongo/db/service_entry_point_common.cpp30
-rw-r--r--src/mongo/db/session_catalog_mongod.cpp2
-rw-r--r--src/mongo/db/transaction_metrics_observer.cpp11
-rw-r--r--src/mongo/db/transaction_participant.cpp90
-rw-r--r--src/mongo/db/transaction_participant.h39
-rw-r--r--src/mongo/db/transaction_participant_test.cpp209
-rw-r--r--src/mongo/dbtests/storage_timestamp_tests.cpp4
12 files changed, 168 insertions, 304 deletions
diff --git a/src/mongo/db/commands/txn_cmds.cpp b/src/mongo/db/commands/txn_cmds.cpp
index ecb756b67d6..8a0fe30e9ec 100644
--- a/src/mongo/db/commands/txn_cmds.cpp
+++ b/src/mongo/db/commands/txn_cmds.cpp
@@ -196,7 +196,7 @@ public:
opCtx, *opCtx->getLogicalSessionId(), *opCtx->getTxnNumber());
}
- txnParticipant.abortActiveTransaction(opCtx);
+ txnParticipant.abortTransaction(opCtx);
if (MONGO_FAIL_POINT(participantReturnNetworkErrorForAbortAfterExecutingAbortLogic)) {
uasserted(ErrorCodes::HostUnreachable,
diff --git a/src/mongo/db/kill_sessions_local.cpp b/src/mongo/db/kill_sessions_local.cpp
index 0e5c13a964d..8a7db69f64c 100644
--- a/src/mongo/db/kill_sessions_local.cpp
+++ b/src/mongo/db/kill_sessions_local.cpp
@@ -86,17 +86,21 @@ void killSessionsAction(
void killSessionsAbortUnpreparedTransactions(OperationContext* opCtx,
const SessionKiller::Matcher& matcher,
ErrorCodes::Error reason) {
- killSessionsAction(
- opCtx,
- matcher,
- [](const ObservableSession& session) {
- auto participant = TransactionParticipant::get(session);
- return participant.transactionIsOpen() && !participant.transactionIsPrepared();
- },
- [](OperationContext* opCtx, const SessionToKill& session) {
- TransactionParticipant::get(session).abortTransactionIfNotPrepared(opCtx);
- },
- reason);
+ killSessionsAction(opCtx,
+ matcher,
+ [](const ObservableSession& session) {
+ auto participant = TransactionParticipant::get(session);
+ return participant.transactionIsInProgress();
+ },
+ [](OperationContext* opCtx, const SessionToKill& session) {
+ auto participant = TransactionParticipant::get(session);
+ // This is the same test as in the filter, but we must check again now
+ // that the session is checked out.
+ if (participant.transactionIsInProgress()) {
+ participant.abortTransaction(opCtx);
+ }
+ },
+ reason);
}
SessionKiller::Result killSessionsLocal(OperationContext* opCtx,
@@ -114,22 +118,31 @@ SessionKiller::Result killSessionsLocal(OperationContext* opCtx,
void killAllExpiredTransactions(OperationContext* opCtx) {
SessionKiller::Matcher matcherAllSessions(
KillAllSessionsByPatternSet{makeKillAllSessionsByPattern(opCtx)});
- killSessionsAction(
- opCtx,
- matcherAllSessions,
- [when = opCtx->getServiceContext()->getPreciseClockSource()->now()](
- const ObservableSession& session) {
- return TransactionParticipant::get(session).expiredAsOf(when);
- },
- [](OperationContext* opCtx, const SessionToKill& session) {
- auto txnParticipant = TransactionParticipant::get(session);
- log()
- << "Aborting transaction with txnNumber " << txnParticipant.getActiveTxnNumber()
- << " on session " << session.getSessionId().getId()
- << " because it has been running for longer than 'transactionLifetimeLimitSeconds'";
- txnParticipant.abortTransactionIfNotPrepared(opCtx);
- },
- ErrorCodes::ExceededTimeLimit);
+ killSessionsAction(opCtx,
+ matcherAllSessions,
+ [when = opCtx->getServiceContext()->getPreciseClockSource()->now()](
+ const ObservableSession& session) {
+ return TransactionParticipant::get(session).expiredAsOf(when);
+ },
+ [](OperationContext* opCtx, const SessionToKill& session) {
+ auto txnParticipant = TransactionParticipant::get(session);
+ // If the transaction is aborted here, it means it was aborted after
+ // the filter. The most likely reason for this is that the transaction
+ // was active and the session kill aborted it. We still want to log
+ // that as aborted due to transactionLifetimeLimitSessions.
+ if (txnParticipant.transactionIsInProgress() ||
+ txnParticipant.transactionIsAborted()) {
+ log() << "Aborting transaction with txnNumber "
+ << txnParticipant.getActiveTxnNumber() << " on session "
+ << session.getSessionId().getId()
+ << " because it has been running for longer than "
+ "'transactionLifetimeLimitSeconds'";
+ if (txnParticipant.transactionIsInProgress()) {
+ txnParticipant.abortTransaction(opCtx);
+ }
+ }
+ },
+ ErrorCodes::ExceededTimeLimit);
}
void killSessionsLocalShutdownAllTransactions(OperationContext* opCtx) {
@@ -156,10 +169,13 @@ void killSessionsAbortAllPreparedTransactions(OperationContext* opCtx) {
return TransactionParticipant::get(session).transactionIsPrepared();
},
[](OperationContext* opCtx, const SessionToKill& session) {
+ // We're holding the RSTL, so the transaction shouldn't be otherwise
+ // affected.
+ invariant(TransactionParticipant::get(session).transactionIsPrepared());
// Abort the prepared transaction and invalidate the session it is
// associated with.
- TransactionParticipant::get(session).abortPreparedTransactionForRollback(
- opCtx);
+ TransactionParticipant::get(session).abortTransaction(opCtx);
+ TransactionParticipant::get(session).invalidate(opCtx);
});
}
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp
index d495bb89f35..c1e2c5722cf 100644
--- a/src/mongo/db/ops/write_ops_exec.cpp
+++ b/src/mongo/db/ops/write_ops_exec.cpp
@@ -252,7 +252,7 @@ bool handleError(OperationContext* opCtx,
}
// If we are in a transaction, we must fail the whole batch.
out->results.emplace_back(ex.toStatus());
- txnParticipant.abortActiveTransaction(opCtx);
+ txnParticipant.abortTransaction(opCtx);
return false;
}
diff --git a/src/mongo/db/repl/transaction_oplog_application.cpp b/src/mongo/db/repl/transaction_oplog_application.cpp
index d06b41c2643..92cbee05379 100644
--- a/src/mongo/db/repl/transaction_oplog_application.cpp
+++ b/src/mongo/db/repl/transaction_oplog_application.cpp
@@ -219,7 +219,7 @@ Status applyAbortTransaction(OperationContext* opCtx,
auto transaction = TransactionParticipant::get(opCtx);
transaction.unstashTransactionResources(opCtx, "abortTransaction");
- transaction.abortActiveTransaction(opCtx);
+ transaction.abortTransaction(opCtx);
return Status::OK();
}
}
diff --git a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp
index cbf6e0e0256..9bfebcef08b 100644
--- a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp
+++ b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp
@@ -280,16 +280,15 @@ public:
{
MongoDOperationContextSession sessionTxnState(opCtx);
auto txnParticipant = TransactionParticipant::get(opCtx);
-
txnParticipant.beginOrContinue(opCtx,
*opCtx->getTxnNumber(),
false /* autocommit */,
boost::none /* startTransaction */);
- try {
- txnParticipant.abortTransactionIfNotPrepared(opCtx);
- } catch (const ExceptionFor<ErrorCodes::TransactionCommitted>&) {
+ if (txnParticipant.transactionIsCommitted())
return;
+ if (txnParticipant.transactionIsInProgress()) {
+ txnParticipant.abortTransaction(opCtx);
}
participantExitPrepareFuture = txnParticipant.onExitPrepare();
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index a4117d0bd56..5b634561906 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -378,6 +378,25 @@ void appendClusterAndOperationTime(OperationContext* opCtx,
operationTime.appendAsOperationTime(commandBodyFieldsBob);
}
+namespace {
+void _abortUnpreparedOrStashPreparedTransaction(
+ OperationContext* opCtx, TransactionParticipant::Participant* txnParticipant) {
+ const bool isPrepared = txnParticipant->transactionIsPrepared();
+ try {
+ if (isPrepared)
+ txnParticipant->stashTransactionResources(opCtx);
+ else if (txnParticipant->transactionIsOpen())
+ txnParticipant->abortTransaction(opCtx);
+ } catch (...) {
+ // It is illegal for this to throw so we catch and log this here for diagnosability.
+ severe() << "Caught exception during transaction " << opCtx->getTxnNumber()
+ << (isPrepared ? " stash " : " abort ") << opCtx->getLogicalSessionId()->toBSON()
+ << ": " << exceptionToStatus();
+ std::terminate();
+ }
+}
+} // namespace
+
void invokeWithSessionCheckedOut(OperationContext* opCtx,
CommandInvocation* invocation,
const OperationSessionInfoFromClient& sessionOptions,
@@ -411,8 +430,11 @@ void invokeWithSessionCheckedOut(OperationContext* opCtx,
// transactions on failure to unstash the transaction resources to opCtx. We don't want to
// have this error guard for beginOrContinue as it can abort the transaction for any
// accidental invalid statements in the transaction.
- auto abortOnError = makeGuard(
- [&txnParticipant, opCtx] { txnParticipant.abortTransactionIfNotPrepared(opCtx); });
+ auto abortOnError = makeGuard([&txnParticipant, opCtx] {
+ if (txnParticipant.transactionIsInProgress()) {
+ txnParticipant.abortTransaction(opCtx);
+ }
+ });
txnParticipant.unstashTransactionResources(opCtx, invocation->definition()->getName());
@@ -420,8 +442,8 @@ void invokeWithSessionCheckedOut(OperationContext* opCtx,
abortOnError.dismiss();
}
- auto guard = makeGuard([&txnParticipant, opCtx] {
- txnParticipant.abortActiveUnpreparedOrStashPreparedTransaction(opCtx);
+ auto guard = makeGuard([opCtx, &txnParticipant] {
+ _abortUnpreparedOrStashPreparedTransaction(opCtx, &txnParticipant);
});
try {
diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp
index 24e6bf62bee..86aeb61fdeb 100644
--- a/src/mongo/db/session_catalog_mongod.cpp
+++ b/src/mongo/db/session_catalog_mongod.cpp
@@ -207,7 +207,7 @@ void abortInProgressTransactions(OperationContext* opCtx) {
auto txnParticipant = TransactionParticipant::get(opCtx);
LOG(3) << "Aborting transaction sessionId: " << txnRecord.getSessionId().toBSON()
<< " txnNumber " << txnRecord.getTxnNum();
- txnParticipant.abortTransactionForStepUp(opCtx);
+ txnParticipant.abortTransaction(opCtx);
}
}
} // namespace
diff --git a/src/mongo/db/transaction_metrics_observer.cpp b/src/mongo/db/transaction_metrics_observer.cpp
index ad0ce535173..e1b36d971bd 100644
--- a/src/mongo/db/transaction_metrics_observer.cpp
+++ b/src/mongo/db/transaction_metrics_observer.cpp
@@ -138,18 +138,12 @@ void TransactionMetricsObserver::_onAbortActive(
// Server wide transactions metrics.
//
serverTransactionsMetrics->decrementCurrentActive();
-
- if (_singleTransactionStats.isPrepared()) {
- serverTransactionsMetrics->incrementTotalPreparedThenAborted();
- serverTransactionsMetrics->decrementCurrentPrepared();
- }
}
void TransactionMetricsObserver::_onAbortInactive(
ServerTransactionsMetrics* serverTransactionsMetrics, TickSource* tickSource, Top* top) {
auto curTick = tickSource->getTicks();
invariant(!_singleTransactionStats.isActive());
- invariant(!_singleTransactionStats.isPrepared());
_onAbort(serverTransactionsMetrics, curTick, tickSource, top);
//
@@ -213,6 +207,11 @@ void TransactionMetricsObserver::_onAbort(ServerTransactionsMetrics* serverTrans
serverTransactionsMetrics->incrementTotalAborted();
serverTransactionsMetrics->decrementCurrentOpen();
+ if (_singleTransactionStats.isPrepared()) {
+ serverTransactionsMetrics->incrementTotalPreparedThenAborted();
+ serverTransactionsMetrics->decrementCurrentPrepared();
+ }
+
auto latency =
durationCount<Microseconds>(_singleTransactionStats.getDuration(tickSource, curTick));
top->incrementGlobalTransactionLatencyStats(static_cast<uint64_t>(latency));
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp
index 1e2327cdd3b..6fbfabbe359 100644
--- a/src/mongo/db/transaction_participant.cpp
+++ b/src/mongo/db/transaction_participant.cpp
@@ -554,6 +554,13 @@ void TransactionParticipant::Participant::beginOrContinueTransactionUnconditiona
if (o().activeTxnNumber != txnNumber) {
_beginMultiDocumentTransaction(opCtx, txnNumber);
}
+
+ // Assume we need to write an abort if we abort this transaction. This method is called only
+ // on secondaries (in which case we never write anything) and when a new primary knows about
+ // an in-progress transaction. If a new primary knows about an in-progress transaction, it
+ // needs an abort oplog entry to be written if aborted (because the new primary could not
+ // have found out if there wasn't an oplog entry for the new primary).
+ p().needToWriteAbortEntry = true;
}
SharedSemiFuture<void> TransactionParticipant::Participant::onExitPrepare() const {
@@ -1040,11 +1047,11 @@ Timestamp TransactionParticipant::Participant::prepareTransaction(
try {
// This shouldn't cause deadlocks with other prepared txns, because the acquisition
- // of RSTL lock inside abortActiveTransaction will be no-op since we already have it.
+ // of RSTL lock inside abortTransaction will be no-op since we already have it.
// This abortGuard gets dismissed before we release the RSTL while transitioning to
// prepared.
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
- abortActiveTransaction(opCtx);
+ abortTransaction(opCtx);
} catch (...) {
// It is illegal for aborting a prepared transaction to fail for any reason, so we crash
// instead.
@@ -1119,6 +1126,7 @@ Timestamp TransactionParticipant::Participant::prepareTransaction(
}
opCtx->recoveryUnit()->setPrepareTimestamp(prepareOplogSlot.getTimestamp());
opCtx->getWriteUnitOfWork()->prepare();
+ p().needToWriteAbortEntry = true;
opCtx->getServiceContext()->getOpObserver()->onTransactionPrepare(
opCtx, reservedSlots, completedTransactionOperations);
@@ -1434,26 +1442,22 @@ void TransactionParticipant::Participant::shutdown(OperationContext* opCtx) {
o(lock).txnResourceStash = boost::none;
}
-void TransactionParticipant::Participant::abortTransactionIfNotPrepared(OperationContext* opCtx) {
- if (!o().txnState.isInProgress()) {
- // We do not want to abort transactions that are prepared unless we get an
- // 'abortTransaction' command.
- return;
- }
-
- _abortTransactionOnSession(opCtx);
-}
-
bool TransactionParticipant::Observer::expiredAsOf(Date_t when) const {
return o().txnState.isInProgress() && o().transactionExpireDate &&
o().transactionExpireDate < when;
}
-void TransactionParticipant::Participant::abortActiveTransaction(OperationContext* opCtx) {
- if (o().txnState.isPrepared()) {
+void TransactionParticipant::Participant::abortTransaction(OperationContext* opCtx) {
+ // Normally, absence of a transaction resource stash indicates an inactive transaction.
+ // However, in the case of a failed "unstash", an active transaction may exist without a stash
+ // and be killed externally. In that case, the opCtx will not have a transaction number.
+ if (o().txnResourceStash || !opCtx->getTxnNumber()) {
+ // Aborting an inactive transaction.
+ _abortTransactionOnSession(opCtx);
+ } else if (o().txnState.isPrepared()) {
_abortActivePreparedTransaction(opCtx);
} else {
- _abortActiveTransaction(opCtx, TransactionState::kInProgress, false);
+ _abortActiveTransaction(opCtx, TransactionState::kInProgress);
}
}
@@ -1476,38 +1480,11 @@ void TransactionParticipant::Participant::_abortActivePreparedTransaction(Operat
replCoord->canAcceptWritesForDatabase(opCtx, "admin"));
}
- _abortActiveTransaction(opCtx, TransactionState::kPrepared, true);
-}
-
-void TransactionParticipant::Participant::abortActiveUnpreparedOrStashPreparedTransaction(
- OperationContext* opCtx) try {
- if (o().txnState.isInSet(TransactionState::kNone | TransactionState::kCommitted |
- TransactionState::kExecutedRetryableWrite)) {
- // If there is no active transaction, do nothing.
- return;
- }
-
- // Stash the transaction if it's in prepared state.
- if (o().txnState.isInSet(TransactionState::kPrepared)) {
- _stashActiveTransaction(opCtx);
- return;
- }
-
- _abortActiveTransaction(opCtx, TransactionState::kInProgress, false /* writeOplog */);
-} catch (...) {
- // It is illegal for this to throw so we catch and log this here for diagnosability.
- severe() << "Caught exception during transaction " << opCtx->getTxnNumber()
- << " abort or stash on " << _sessionId().toBSON() << " in state " << o().txnState
- << ": " << exceptionToStatus();
- std::terminate();
-}
-
-void TransactionParticipant::Participant::abortTransactionForStepUp(OperationContext* opCtx) {
- _abortActiveTransaction(opCtx, TransactionState::kInProgress, true);
+ _abortActiveTransaction(opCtx, TransactionState::kPrepared);
}
void TransactionParticipant::Participant::_abortActiveTransaction(
- OperationContext* opCtx, TransactionState::StateSet expectedStates, bool writeOplog) {
+ OperationContext* opCtx, TransactionState::StateSet expectedStates) {
invariant(!o().txnResourceStash);
invariant(!o().txnState.isCommittingWithPrepare());
@@ -1522,7 +1499,7 @@ void TransactionParticipant::Participant::_abortActiveTransaction(
// OpObserver.
boost::optional<OplogSlotReserver> oplogSlotReserver;
boost::optional<OplogSlot> abortOplogSlot;
- if (opCtx->writesAreReplicated() && writeOplog) {
+ if (opCtx->writesAreReplicated() && p().needToWriteAbortEntry) {
oplogSlotReserver.emplace(opCtx);
abortOplogSlot = oplogSlotReserver->getLastSlot();
}
@@ -1603,7 +1580,10 @@ void TransactionParticipant::Participant::_cleanUpTxnResourceOnOpCtx(
// Reset the WUOW. We should be able to abort empty transactions that don't have WUOW.
if (opCtx->getWriteUnitOfWork()) {
- invariant(opCtx->lockState()->isRSTLLocked());
+ // We could have failed trying to get the initial global lock; in that case we will have a
+ // WriteUnitOfWork but not have allocated the storage transaction. That is the only case
+ // where it is legal to abort a unit of work without the RSTL.
+ invariant(opCtx->lockState()->isRSTLLocked() || !opCtx->recoveryUnit()->inActiveTxn());
opCtx->setWriteUnitOfWork(nullptr);
}
@@ -2072,6 +2052,7 @@ void TransactionParticipant::Participant::_resetTransactionState(
o(wl).prepareOpTime = repl::OpTime();
o(wl).recoveryPrepareOpTime = repl::OpTime();
p().autoCommit = boost::none;
+ p().needToWriteAbortEntry = false;
// Release any locks held by this participant and abort the storage transaction.
o(wl).txnResourceStash = boost::none;
@@ -2092,23 +2073,6 @@ void TransactionParticipant::Participant::invalidate(OperationContext* opCtx) {
_resetTransactionState(lg, TransactionState::kNone);
}
-void TransactionParticipant::Participant::abortPreparedTransactionForRollback(
- OperationContext* opCtx) {
- uassert(51030,
- str::stream() << "Cannot call abortPreparedTransactionForRollback on unprepared "
- << "transaction.",
- o().txnState.isPrepared());
-
- stdx::lock_guard<Client> lg(*opCtx->getClient());
-
- // It should be safe to clear transactionOperationBytes and transactionOperations because
- // we only modify these variables when adding an operation to a transaction. Since this
- // transaction is already prepared, we cannot add more operations to it. We will have this
- // in the prepare oplog entry.
- _invalidate(lg);
- _resetTransactionState(lg, TransactionState::kNone);
-}
-
boost::optional<repl::OplogEntry> TransactionParticipant::Participant::checkStatementExecuted(
OperationContext* opCtx, StmtId stmtId) const {
const auto stmtTimestamp = _checkStatementExecuted(stmtId);
diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h
index 897637b9f32..93a509a90c1 100644
--- a/src/mongo/db/transaction_participant.h
+++ b/src/mongo/db/transaction_participant.h
@@ -495,34 +495,10 @@ public:
Timestamp commitTimestamp,
boost::optional<repl::OpTime> commitOplogEntryOpTime);
- /**
- * Aborts the transaction, if it is not in the "prepared" state.
- */
- void abortTransactionIfNotPrepared(OperationContext* opCtx);
-
/*
* Aborts the transaction, releasing transaction resources.
*/
- void abortActiveTransaction(OperationContext* opCtx);
-
- /*
- * If the transaction is prepared, stash its resources. If not, it's the same as
- * abortActiveTransaction.
- */
- void abortActiveUnpreparedOrStashPreparedTransaction(OperationContext* opCtx);
-
- /**
- * Abort the transaction and write an abort oplog entry unconditionally.
- */
- void abortTransactionForStepUp(OperationContext* opCtx);
-
- /**
- * Aborts the storage transaction of the prepared transaction on this participant by
- * releasing its resources. Also invalidates the session and the current transaction state.
- * Avoids writing any oplog entries or making any changes to the transaction table since the
- * state for prepared transactions will be re-constituted during replication recovery.
- */
- void abortPreparedTransactionForRollback(OperationContext* opCtx);
+ void abortTransaction(OperationContext* opCtx);
/**
* Adds a stored operation to the list of stored operations for the current multi-document
@@ -701,11 +677,10 @@ public:
void _stashActiveTransaction(OperationContext* opCtx);
// Abort the transaction if it's in one of the expected states and clean up the transaction
- // states associated with the opCtx.
- // If 'writeOplog' is true, logs an 'abortTransaction' oplog entry if writes are replicated.
+ // states associated with the opCtx. Write an abort oplog entry if specified by the
+ // needToWriteAbortEntry state bool.
void _abortActiveTransaction(OperationContext* opCtx,
- TransactionState::StateSet expectedStates,
- bool writeOplog);
+ TransactionState::StateSet expectedStates);
// Aborts a prepared transaction.
void _abortActivePreparedTransaction(OperationContext* opCtx);
@@ -954,6 +929,12 @@ private:
// opTime. Used for fast retryability check and retrieving the previous write's data without
// having to scan through the oplog.
CommittedStatementTimestampMap activeTxnCommittedStatements;
+
+ // Set to true if we need to write an "abort" oplog entry in the case of an abort. This
+ // is the case when we have (or may have) written or replicated an oplog entry for the
+ // transaction.
+ bool needToWriteAbortEntry{false};
+
} _p;
};
diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp
index 0947c8580ae..497ef46b756 100644
--- a/src/mongo/db/transaction_participant_test.cpp
+++ b/src/mongo/db/transaction_participant_test.cpp
@@ -495,7 +495,7 @@ TEST_F(TxnParticipantTest, AbortClearsStoredStatements) {
// The transaction machinery cannot store an empty locker.
{ Lock::GlobalLock lk(opCtx(), MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); }
txnParticipant.stashTransactionResources(opCtx());
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(txnParticipant.getTransactionOperationsForTest().empty());
ASSERT_TRUE(txnParticipant.transactionIsAborted());
}
@@ -709,7 +709,7 @@ TEST_F(TxnParticipantTest, EmptyTransactionAbort) {
// The transaction machinery cannot store an empty locker.
{ Lock::GlobalLock lk(opCtx(), MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); }
txnParticipant.stashTransactionResources(opCtx());
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(txnParticipant.transactionIsAborted());
}
@@ -723,37 +723,10 @@ TEST_F(TxnParticipantTest, EmptyPreparedTransactionAbort) {
// The transaction machinery cannot store an empty locker.
{ Lock::GlobalLock lk(opCtx(), MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); }
txnParticipant.prepareTransaction(opCtx(), {});
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(txnParticipant.transactionIsAborted());
}
-TEST_F(TxnParticipantTest, KillSessionsDuringPrepareDoesNotAbortTransaction) {
- auto sessionCheckout = checkOutSession();
- auto txnParticipant = TransactionParticipant::get(opCtx());
-
- txnParticipant.unstashTransactionResources(opCtx(), "prepareTransaction");
-
- auto ruPrepareTimestamp = Timestamp();
- auto originalFn = _opObserver->onTransactionPrepareFn;
- _opObserver->onTransactionPrepareFn = [&]() {
- originalFn();
-
- ruPrepareTimestamp = opCtx()->recoveryUnit()->getPrepareTimestamp();
- ASSERT_FALSE(ruPrepareTimestamp.isNull());
-
- // The transaction may be aborted without checking out the txnParticipant.
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
- ASSERT_FALSE(txnParticipant.transactionIsAborted());
- };
-
- // Check that prepareTimestamp gets set.
- auto prepareTimestamp = txnParticipant.prepareTransaction(opCtx(), {});
- ASSERT_EQ(ruPrepareTimestamp, prepareTimestamp);
-
- ASSERT(_opObserver->transactionPrepared);
- ASSERT_FALSE(txnParticipant.transactionIsAborted());
-}
-
TEST_F(TxnParticipantTest, ThrowDuringOnTransactionPrepareAbortsTransaction) {
auto sessionCheckout = checkOutSession();
auto txnParticipant = TransactionParticipant::get(opCtx());
@@ -829,7 +802,7 @@ TEST_F(TxnParticipantTest, StepDownAfterPrepareDoesNotBlock) {
};
runFunctionFromDifferentOpCtx(func);
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(_opObserver->transactionAborted);
ASSERT(txnParticipant.transactionIsAborted());
}
@@ -861,7 +834,7 @@ TEST_F(TxnParticipantTest, StepDownDuringAbortSucceeds) {
ASSERT_OK(repl::ReplicationCoordinator::get(opCtx())->setFollowerMode(
repl::MemberState::RS_SECONDARY));
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(_opObserver->transactionAborted);
ASSERT(txnParticipant.transactionIsAborted());
}
@@ -876,7 +849,7 @@ TEST_F(TxnParticipantTest, StepDownDuringPreparedAbortFails) {
ASSERT_OK(repl::ReplicationCoordinator::get(opCtx())->setFollowerMode(
repl::MemberState::RS_SECONDARY));
ASSERT_THROWS_CODE(
- txnParticipant.abortActiveTransaction(opCtx()), AssertionException, ErrorCodes::NotMaster);
+ txnParticipant.abortTransaction(opCtx()), AssertionException, ErrorCodes::NotMaster);
}
TEST_F(TxnParticipantTest, StepDownDuringPreparedCommitFails) {
@@ -932,7 +905,7 @@ TEST_F(TxnParticipantTest, StepDownDuringPreparedAbortReleasesRSTL) {
ASSERT_OK(repl::ReplicationCoordinator::get(opCtx())->setFollowerMode(
repl::MemberState::RS_SECONDARY));
ASSERT_THROWS_CODE(
- txnParticipant.abortActiveTransaction(opCtx()), AssertionException, ErrorCodes::NotMaster);
+ txnParticipant.abortTransaction(opCtx()), AssertionException, ErrorCodes::NotMaster);
ASSERT_EQ(opCtx()->lockState()->getLockMode(resourceIdReplicationStateTransitionLock),
MODE_NONE);
@@ -1015,7 +988,7 @@ TEST_F(TxnParticipantTest, ThrowDuringUnpreparedCommitLetsTheAbortAtEntryPointTo
ASSERT_FALSE(txnParticipant.transactionIsCommitted());
// Simulate the abort at entry point.
- txnParticipant.abortActiveUnpreparedOrStashPreparedTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(txnParticipant.transactionIsAborted());
}
@@ -1033,56 +1006,6 @@ TEST_F(TxnParticipantTest, ContinuingATransactionWithNoResourcesAborts) {
ErrorCodes::NoSuchTransaction);
}
-TEST_F(TxnParticipantTest, KillSessionsDoesNotAbortPreparedTransactions) {
- auto sessionCheckout = checkOutSession();
- auto txnParticipant = TransactionParticipant::get(opCtx());
-
- txnParticipant.unstashTransactionResources(opCtx(), "insert");
-
- auto ruPrepareTimestamp = Timestamp();
- auto originalFn = _opObserver->onTransactionPrepareFn;
- _opObserver->onTransactionPrepareFn = [&]() {
- originalFn();
- ruPrepareTimestamp = opCtx()->recoveryUnit()->getPrepareTimestamp();
- ASSERT_FALSE(ruPrepareTimestamp.isNull());
- };
-
- // Check that prepareTimestamp gets set.
- auto prepareTimestamp = txnParticipant.prepareTransaction(opCtx(), {});
- ASSERT_EQ(ruPrepareTimestamp, prepareTimestamp);
-
- txnParticipant.stashTransactionResources(opCtx());
-
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
- ASSERT_FALSE(txnParticipant.transactionIsAborted());
- ASSERT(_opObserver->transactionPrepared);
-}
-
-TEST_F(TxnParticipantTest, CannotAbortArbitraryPreparedTransactions) {
- auto sessionCheckout = checkOutSession();
- auto txnParticipant = TransactionParticipant::get(opCtx());
-
- txnParticipant.unstashTransactionResources(opCtx(), "insert");
-
- auto ruPrepareTimestamp = Timestamp();
- auto originalFn = _opObserver->onTransactionPrepareFn;
- _opObserver->onTransactionPrepareFn = [&]() {
- originalFn();
- ruPrepareTimestamp = opCtx()->recoveryUnit()->getPrepareTimestamp();
- ASSERT_FALSE(ruPrepareTimestamp.isNull());
- };
-
- // Check that prepareTimestamp gets set.
- auto prepareTimestamp = txnParticipant.prepareTransaction(opCtx(), {});
- ASSERT_EQ(ruPrepareTimestamp, prepareTimestamp);
-
- txnParticipant.stashTransactionResources(opCtx());
-
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
- ASSERT(!txnParticipant.transactionIsAborted());
- ASSERT(_opObserver->transactionPrepared);
-}
-
TEST_F(TxnParticipantTest, CannotStartNewTransactionIfNotPrimary) {
ASSERT_OK(repl::ReplicationCoordinator::get(opCtx())->setFollowerMode(
repl::MemberState::RS_SECONDARY));
@@ -1190,23 +1113,6 @@ TEST_F(TxnParticipantTest, CannotInsertInPreparedTransaction) {
ASSERT(_opObserver->transactionPrepared);
}
-TEST_F(TxnParticipantTest, ImplicitAbortDoesNotAbortPreparedTransaction) {
- auto outerScopedSession = checkOutSession();
- auto txnParticipant = TransactionParticipant::get(opCtx());
-
- txnParticipant.unstashTransactionResources(opCtx(), "insert");
- auto operation = repl::OplogEntry::makeInsertOperation(kNss, _uuid, BSON("TestValue" << 0));
- txnParticipant.addTransactionOperation(opCtx(), operation);
-
- txnParticipant.prepareTransaction(opCtx(), {});
-
- // The next command throws an exception and wants to abort the transaction.
- // This is a no-op.
- txnParticipant.abortActiveUnpreparedOrStashPreparedTransaction(opCtx());
- ASSERT_FALSE(txnParticipant.transactionIsAborted());
- ASSERT_TRUE(_opObserver->transactionPrepared);
-}
-
DEATH_TEST_F(TxnParticipantTest,
AbortIsIllegalDuringCommittingPreparedTransaction,
"isCommittingWithPrepare") {
@@ -1224,7 +1130,7 @@ DEATH_TEST_F(TxnParticipantTest,
Timestamp commitTimestamp,
const std::vector<repl::ReplOperation>& statements) {
// Hit an invariant. This should never happen.
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_FALSE(txnParticipant.transactionIsAborted());
};
@@ -1334,7 +1240,7 @@ protected:
auto txnParticipant = TransactionParticipant::get(opCtx());
ASSERT(txnParticipant.transactionIsOpen());
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
txnParticipant.beginOrContinue(
@@ -1390,7 +1296,7 @@ protected:
txnParticipant.prepareTransaction(opCtx(), {});
ASSERT(txnParticipant.transactionIsPrepared());
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
startTransaction = true;
@@ -1504,9 +1410,8 @@ TEST_F(TxnParticipantTest, ThrowDuringUnpreparedOnTransactionAbort) {
_opObserver->onTransactionAbortThrowsException = true;
- ASSERT_THROWS_CODE(txnParticipant.abortActiveTransaction(opCtx()),
- AssertionException,
- ErrorCodes::OperationFailed);
+ ASSERT_THROWS_CODE(
+ txnParticipant.abortTransaction(opCtx()), AssertionException, ErrorCodes::OperationFailed);
}
TEST_F(TxnParticipantTest, ThrowDuringPreparedOnTransactionAbortIsFatal) {
@@ -1517,9 +1422,8 @@ TEST_F(TxnParticipantTest, ThrowDuringPreparedOnTransactionAbortIsFatal) {
_opObserver->onTransactionAbortThrowsException = true;
- ASSERT_THROWS_CODE(txnParticipant.abortActiveTransaction(opCtx()),
- AssertionException,
- ErrorCodes::OperationFailed);
+ ASSERT_THROWS_CODE(
+ txnParticipant.abortTransaction(opCtx()), AssertionException, ErrorCodes::OperationFailed);
}
TEST_F(TxnParticipantTest, InterruptedSessionsCannotBePrepared) {
@@ -1584,7 +1488,7 @@ TEST_F(TxnParticipantTest, ReacquireLocksForPreparedTransactionsOnStepUp) {
auto txnParticipant = TransactionParticipant::get(opCtx());
ASSERT(txnParticipant.getTxnResourceStashLockerForTest()->isLocked());
txnParticipant.unstashTransactionResources(opCtx(), "abortTransaction");
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
}
}
@@ -1679,7 +1583,7 @@ TEST_F(TransactionsMetricsTest, IncrementTotalAbortedUponAbort) {
unsigned long long beforeAbortCount =
ServerTransactionsMetrics::get(opCtx())->getTotalAborted();
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
// Assert that the aborted counter is incremented by 1.
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getTotalAborted(), beforeAbortCount + 1U);
@@ -1694,7 +1598,7 @@ TEST_F(TransactionsMetricsTest, IncrementTotalPreparedThenAborted) {
txnParticipant.unstashTransactionResources(opCtx(), "prepareTransaction");
txnParticipant.prepareTransaction(opCtx(), {});
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getTotalPreparedThenAborted(),
beforePreparedThenAbortedCount + 1U);
@@ -1728,7 +1632,7 @@ TEST_F(TransactionsMetricsTest, IncrementCurrentPreparedWithAbort) {
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentPrepared(),
beforeCurrentPrepared + 1U);
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentPrepared(), beforeCurrentPrepared);
}
@@ -1761,7 +1665,8 @@ TEST_F(TransactionsMetricsTest, NoPreparedMetricsChangesAfterExceptionInPrepare)
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getTotalPreparedThenAborted(),
beforeTotalPreparedThenAborted);
- txnParticipant.abortActiveTransaction(opCtx());
+ if (txnParticipant.transactionIsOpen())
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentPrepared(), beforeCurrentPrepared);
@@ -1790,7 +1695,7 @@ TEST_F(TransactionsMetricsTest, TrackTotalOpenTransactionsWithAbort) {
beforeTransactionStart + 1U);
// Tests that aborting a transaction decrements the open transactions counter by 1.
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentOpen(), beforeTransactionStart);
}
@@ -1886,7 +1791,7 @@ TEST_F(TransactionsMetricsTest, TrackTotalActiveAndInactiveTransactionsWithStash
beforeInactiveCounter + 1U);
// Tests that aborting a stashed transaction decrements the inactive counter only.
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentActive(), beforeActiveCounter);
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentInactive(), beforeInactiveCounter);
}
@@ -1911,7 +1816,7 @@ TEST_F(TransactionsMetricsTest, TrackTotalActiveAndInactiveTransactionsWithUnsta
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentInactive(), beforeInactiveCounter);
// Tests that aborting a stashed transaction decrements the active counter only.
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentActive(), beforeActiveCounter);
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentInactive(), beforeInactiveCounter);
}
@@ -1996,7 +1901,7 @@ TEST_F(TransactionsMetricsTest,
beforeActivePreparedCounter + 1U);
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentInactive(),
beforeInactivePreparedCounter);
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.transactionIsAborted());
ASSERT_EQ(ServerTransactionsMetrics::get(opCtx())->getCurrentActive(),
beforeActivePreparedCounter);
@@ -2091,7 +1996,7 @@ TEST_F(TransactionsMetricsTest, SingleTransactionStatsDurationShouldBeSetUponAbo
// Advance the clock.
tickSource->advance(Microseconds(100));
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getDuration(tickSource,
tickSource->getTicks()),
Microseconds(100));
@@ -2111,7 +2016,7 @@ TEST_F(TransactionsMetricsTest, SingleTransactionStatsPreparedDurationShouldBeSe
txnParticipant.prepareTransaction(opCtx(), {});
tickSource->advance(Microseconds(100));
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getPreparedDuration(
tickSource, tickSource->getTicks()),
Microseconds(100));
@@ -2202,7 +2107,7 @@ TEST_F(TransactionsMetricsTest, SingleTransactionStatsDurationShouldKeepIncreasi
tickSource->advance(Microseconds(100));
// Abort the transaction and check duration.
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getDuration(tickSource,
tickSource->getTicks()),
Microseconds(200));
@@ -2236,7 +2141,7 @@ TEST_F(TransactionsMetricsTest,
tickSource->advance(Microseconds(100));
// Abort the prepared transaction and check the prepared duration.
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getPreparedDuration(
tickSource, tickSource->getTicks()),
Microseconds(200));
@@ -2309,7 +2214,7 @@ TEST_F(TransactionsMetricsTest, TimeActiveMicrosShouldBeSetUponUnstashAndAbort)
txnParticipant.unstashTransactionResources(opCtx(), "insert");
tickSource->advance(Microseconds(100));
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
// Time active should have increased.
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getTimeActiveMicros(
@@ -2338,7 +2243,7 @@ TEST_F(TransactionsMetricsTest, TimeActiveMicrosShouldNotBeSetUponAbortOnly) {
// Advance clock during inactive period.
tickSource->advance(Microseconds(100));
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
// Time active should still be zero.
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getTimeActiveMicros(
@@ -2531,7 +2436,7 @@ TEST_F(TransactionsMetricsTest, AdditiveMetricsObjectsShouldBeAddedTogetherUponA
txnParticipant.unstashTransactionResources(opCtx(), "insert");
// The transaction machinery cannot store an empty locker.
{ Lock::GlobalLock lk(opCtx(), MODE_IX, Date_t::now(), Lock::InterruptBehavior::kThrow); }
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT(txnParticipant.getSingleTransactionStatsForTest().getOpDebug()->additiveMetrics.equals(
additiveMetricsToCompare));
@@ -2595,7 +2500,7 @@ TEST_F(TransactionsMetricsTest, TimeInactiveMicrosShouldBeSetUponUnstashAndAbort
Microseconds{100});
txnParticipant.unstashTransactionResources(opCtx(), "insert");
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_EQ(txnParticipant.getSingleTransactionStatsForTest().getTimeInactiveMicros(
tickSource, tickSource->getTicks()),
@@ -2928,7 +2833,7 @@ TEST_F(TransactionsMetricsTest, LastClientInfoShouldUpdateUponAbort) {
auto sessionCheckout = checkOutSession();
auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant.unstashTransactionResources(opCtx(), "insert");
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
// LastClientInfo should have been set.
auto lastClientInfo = txnParticipant.getSingleTransactionStatsForTest().getLastClientInfo();
@@ -3198,7 +3103,7 @@ TEST_F(TransactionsMetricsTest, TestTransactionInfoForLogAfterAbort) {
auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant.unstashTransactionResources(opCtx(), "abortTransaction");
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
const auto lockerInfo = opCtx()->lockState()->getLockerInfo(boost::none);
ASSERT(lockerInfo);
@@ -3242,7 +3147,7 @@ TEST_F(TransactionsMetricsTest, TestPreparedTransactionInfoForLogAfterAbort) {
txnParticipant.prepareTransaction(opCtx(), {});
tickSource->advance(Microseconds(10));
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
const auto lockerInfo = opCtx()->lockState()->getLockerInfo(boost::none);
ASSERT(lockerInfo);
@@ -3385,7 +3290,7 @@ TEST_F(TransactionsMetricsTest, LogTransactionInfoAfterSlowAbort) {
tickSource->advance(Microseconds(11 * 1000));
startCapturingLogMessages();
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
stopCapturingLogMessages();
const auto lockerInfo = opCtx()->lockState()->getLockerInfo(boost::none);
@@ -3430,7 +3335,7 @@ TEST_F(TransactionsMetricsTest, LogPreparedTransactionInfoAfterSlowAbort) {
auto prepareOpTime = txnParticipant.getPrepareOpTime();
startCapturingLogMessages();
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
stopCapturingLogMessages();
const auto lockerInfo = opCtx()->lockState()->getLockerInfo(boost::none);
@@ -3528,7 +3433,7 @@ TEST_F(TransactionsMetricsTest, LogTransactionInfoAfterSlowStashedAbort) {
tickSource->advance(Microseconds(11 * 1000));
startCapturingLogMessages();
- txnParticipant.abortTransactionIfNotPrepared(opCtx());
+ txnParticipant.abortTransaction(opCtx());
stopCapturingLogMessages();
std::string expectedTransactionInfo = "transaction parameters";
@@ -3613,9 +3518,10 @@ TEST_F(TxnParticipantTest, RollbackResetsInMemoryStateOfPreparedTransaction) {
ASSERT_EQ(txnParticipant.getPrepareOpTime().getTimestamp(), prepareTimestamp);
ASSERT_NE(txnParticipant.getActiveTxnNumber(), kUninitializedTxnNumber);
- txnParticipant.abortPreparedTransactionForRollback(opCtx());
+ txnParticipant.abortTransaction(opCtx());
+ txnParticipant.invalidate(opCtx());
- // After calling abortPreparedTransactionForRollback, the state of txnParticipant should be
+ // After calling abortTransaction and invalidate, the state of txnParticipant should be
// invalidated.
ASSERT_FALSE(txnParticipant.transactionIsPrepared());
ASSERT_EQ(txnParticipant.getTransactionOperationsForTest().size(), 0U);
@@ -3728,7 +3634,7 @@ TEST_F(TxnParticipantTest, AbortTransactionOnSessionCheckoutWithoutRefresh) {
ASSERT_EQ(txnParticipant.getActiveTxnNumber(), txnNumber);
txnParticipant.unstashTransactionResources(opCtx(), "abortTransaction");
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(txnParticipant.transactionIsAborted());
}
@@ -3798,7 +3704,7 @@ TEST_F(TxnParticipantTest, ResponseMetadataHasReadOnlyFalseIfAborted) {
txnParticipant.unstashTransactionResources(opCtx(), "find");
ASSERT_TRUE(txnParticipant.getResponseMetadata().getReadOnly());
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_FALSE(txnParticipant.getResponseMetadata().getReadOnly());
}
@@ -3904,7 +3810,7 @@ TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnAbortAfterPrepare) {
const auto exitPrepareFuture = txnParticipant.onExitPrepare();
ASSERT_FALSE(exitPrepareFuture.isReady());
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
ASSERT_TRUE(exitPrepareFuture.isReady());
// Once the promise has been fulfilled, new callers of onExitPrepare should immediately be
@@ -3912,7 +3818,7 @@ TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnAbortAfterPrepare) {
ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
// abortTransaction is retryable, but does not cause the completion promise to be set again.
- txnParticipant.abortActiveTransaction(opCtx());
+ txnParticipant.abortTransaction(opCtx());
}
TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnCommitAfterPrepare) {
@@ -3941,28 +3847,5 @@ TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnCommitAfterPrepare) {
ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
}
-TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnAbortPreparedTransactionForRollback) {
- MongoDOperationContextSession opCtxSession(opCtx());
- auto txnParticipant = TransactionParticipant::get(opCtx());
-
- txnParticipant.beginOrContinue(
- opCtx(), *opCtx()->getTxnNumber(), false /* autocommit */, true /* startTransaction */);
- ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
-
- txnParticipant.unstashTransactionResources(opCtx(), "find");
- ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
-
- const auto prepareOpTime = repl::OpTime({3, 2}, 0);
- txnParticipant.prepareTransaction(opCtx(), prepareOpTime);
- const auto exitPrepareFuture = txnParticipant.onExitPrepare();
- ASSERT_FALSE(exitPrepareFuture.isReady());
-
- txnParticipant.abortPreparedTransactionForRollback(opCtx());
- ASSERT_TRUE(exitPrepareFuture.isReady());
-
- // Once the promise has been fulfilled, new callers of onExitPrepare should immediately be
- // ready.
- ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
-}
} // namespace
} // namespace mongo
diff --git a/src/mongo/dbtests/storage_timestamp_tests.cpp b/src/mongo/dbtests/storage_timestamp_tests.cpp
index bf5deafc338..ea4dc1e148b 100644
--- a/src/mongo/dbtests/storage_timestamp_tests.cpp
+++ b/src/mongo/dbtests/storage_timestamp_tests.cpp
@@ -3139,7 +3139,7 @@ public:
txnParticipant.unstashTransactionResources(_opCtx, "abortTransaction");
- txnParticipant.abortActiveTransaction(_opCtx);
+ txnParticipant.abortTransaction(_opCtx);
txnParticipant.stashTransactionResources(_opCtx);
{
@@ -3361,7 +3361,7 @@ public:
}
txnParticipant.unstashTransactionResources(_opCtx, "abortTransaction");
- txnParticipant.abortActiveTransaction(_opCtx);
+ txnParticipant.abortTransaction(_opCtx);
assertNoStartOpTime();
txnParticipant.stashTransactionResources(_opCtx);