summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2018-12-19 15:51:56 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2018-12-22 09:11:43 -0500
commit8a40fbeb320c2109d81c933c2f6f6b9fc65e017f (patch)
treea10a2631c4a9d9898c9efcb3bd02985fabbf383e /src/mongo/db
parent402ea2b4d8e616878c2e14a5fb6f2f86faaaada0 (diff)
downloadmongo-8a40fbeb320c2109d81c933c2f6f6b9fc65e017f.tar.gz
SERVER-38713 Get rid of transaction number equality checking from checkStatementExecuted
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp3
-rw-r--r--src/mongo/db/op_observer_impl_test.cpp54
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp9
-rw-r--r--src/mongo/db/s/session_catalog_migration_destination.cpp23
-rw-r--r--src/mongo/db/s/session_catalog_migration_destination_test.cpp6
-rw-r--r--src/mongo/db/session_catalog_mongod.cpp9
-rw-r--r--src/mongo/db/transaction_participant.cpp60
-rw-r--r--src/mongo/db/transaction_participant.h19
-rw-r--r--src/mongo/db/transaction_participant_retryable_writes_test.cpp91
-rw-r--r--src/mongo/db/transaction_participant_test.cpp2
10 files changed, 86 insertions, 190 deletions
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index dfb83807cc5..b3920af779d 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -325,8 +325,7 @@ public:
const auto stmtId = 0;
if (opCtx->getTxnNumber() && !inTransaction) {
const auto txnParticipant = TransactionParticipant::get(opCtx);
- if (auto entry =
- txnParticipant->checkStatementExecuted(opCtx, *opCtx->getTxnNumber(), stmtId)) {
+ if (auto entry = txnParticipant->checkStatementExecuted(stmtId)) {
RetryableWritesStats::get(opCtx)->incrementRetriedCommandsCount();
RetryableWritesStats::get(opCtx)->incrementRetriedStatementsCount();
parseOplogEntryForFindAndModify(opCtx, args, *entry, &result);
diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp
index 1fb9711b7c2..b802c28a301 100644
--- a/src/mongo/db/op_observer_impl_test.cpp
+++ b/src/mongo/db/op_observer_impl_test.cpp
@@ -332,56 +332,6 @@ public:
};
TEST_F(OpObserverSessionCatalogRollbackTest,
- OnRollbackInvalidatesSessionCatalogIfSessionOpsRolledBack) {
- const NamespaceString nss("testDB", "testColl");
-
- // Create a session.
- auto sessionCatalog = SessionCatalog::get(getServiceContext());
- auto sessionId = makeLogicalSessionIdForTest();
-
- const TxnNumber txnNum = 0;
- const StmtId stmtId = 1000;
-
- {
- auto opCtx = cc().makeOperationContext();
- opCtx->setLogicalSessionId(sessionId);
-
- // Create a session and sync it from disk
- auto session = sessionCatalog->checkOutSession(opCtx.get());
- const auto txnParticipant = TransactionParticipant::get(session.get());
- txnParticipant->refreshFromStorageIfNeeded();
-
- // Simulate a write occurring on that session
- simulateSessionWrite(opCtx.get(), txnParticipant, nss, txnNum, stmtId);
-
- // Check that the statement executed
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, stmtId));
- }
-
- // The OpObserver should invalidate in-memory session state, so the check after this should
- // fail.
- {
- auto opCtx = cc().makeOperationContext();
-
- OpObserverImpl opObserver;
- OpObserver::RollbackObserverInfo rbInfo;
- rbInfo.rollbackSessionIds = {UUID::gen()};
- opObserver.onReplicationRollback(opCtx.get(), rbInfo);
- }
-
- {
- auto opCtx = cc().makeOperationContext();
- opCtx->setLogicalSessionId(sessionId);
-
- auto session = sessionCatalog->checkOutSession(opCtx.get());
- const auto txnParticipant = TransactionParticipant::get(session.get());
- ASSERT_THROWS_CODE(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, stmtId),
- DBException,
- ErrorCodes::ConflictingOperationInProgress);
- }
-}
-
-TEST_F(OpObserverSessionCatalogRollbackTest,
OnRollbackDoesntInvalidateSessionCatalogIfNoSessionOpsRolledBack) {
const NamespaceString nss("testDB", "testColl");
@@ -404,7 +354,7 @@ TEST_F(OpObserverSessionCatalogRollbackTest,
simulateSessionWrite(opCtx.get(), txnParticipant, nss, txnNum, stmtId);
// Check that the statement executed
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, stmtId));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(stmtId));
}
// Because there are no sessions to rollback, the OpObserver should not invalidate the in-memory
@@ -423,7 +373,7 @@ TEST_F(OpObserverSessionCatalogRollbackTest,
auto session = sessionCatalog->checkOutSession(opCtx.get());
const auto txnParticipant = TransactionParticipant::get(session.get());
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, stmtId));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(stmtId));
}
}
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp
index 09b2d8f2fe8..a6301e041a4 100644
--- a/src/mongo/db/ops/write_ops_exec.cpp
+++ b/src/mongo/db/ops/write_ops_exec.cpp
@@ -520,8 +520,7 @@ WriteResult performInserts(OperationContext* opCtx,
const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++);
if (opCtx->getTxnNumber()) {
if (!txnParticipant->inMultiDocumentTransaction() &&
- txnParticipant->checkStatementExecutedNoOplogEntryFetch(*opCtx->getTxnNumber(),
- stmtId)) {
+ txnParticipant->checkStatementExecutedNoOplogEntryFetch(stmtId)) {
containsRetry = true;
RetryableWritesStats::get(opCtx)->incrementRetriedStatementsCount();
out.results.emplace_back(makeWriteResultForInsertOrDeleteRetry());
@@ -729,8 +728,7 @@ WriteResult performUpdates(OperationContext* opCtx, const write_ops::Update& who
const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++);
if (opCtx->getTxnNumber()) {
if (!txnParticipant->inMultiDocumentTransaction()) {
- if (auto entry = txnParticipant->checkStatementExecuted(
- opCtx, *opCtx->getTxnNumber(), stmtId)) {
+ if (auto entry = txnParticipant->checkStatementExecuted(stmtId)) {
containsRetry = true;
RetryableWritesStats::get(opCtx)->incrementRetriedStatementsCount();
out.results.emplace_back(parseOplogEntryForUpdate(*entry));
@@ -869,8 +867,7 @@ WriteResult performDeletes(OperationContext* opCtx, const write_ops::Delete& who
const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++);
if (opCtx->getTxnNumber()) {
if (!txnParticipant->inMultiDocumentTransaction() &&
- txnParticipant->checkStatementExecutedNoOplogEntryFetch(*opCtx->getTxnNumber(),
- stmtId)) {
+ txnParticipant->checkStatementExecutedNoOplogEntryFetch(stmtId)) {
containsRetry = true;
RetryableWritesStats::get(opCtx)->incrementRetriedStatementsCount();
out.results.emplace_back(makeWriteResultForInsertOrDeleteRetry());
diff --git a/src/mongo/db/s/session_catalog_migration_destination.cpp b/src/mongo/db/s/session_catalog_migration_destination.cpp
index 036e319c59e..0e04d7462c6 100644
--- a/src/mongo/db/s/session_catalog_migration_destination.cpp
+++ b/src/mongo/db/s/session_catalog_migration_destination.cpp
@@ -250,10 +250,27 @@ ProcessOplogResult processSessionOplog(OperationContext* opCtx,
auto scopedSession = SessionCatalog::get(opCtx)->checkOutSession(opCtx, result.sessionId);
auto const txnParticipant = TransactionParticipant::get(scopedSession.get());
txnParticipant->refreshFromStorageIfNeeded();
+ txnParticipant->beginOrContinue(result.txnNum, boost::none, boost::none);
- if (!txnParticipant->onMigrateBeginOnPrimary(opCtx, result.txnNum, stmtId)) {
- // Don't continue migrating the transaction history
- return lastResult;
+ try {
+ if (txnParticipant->checkStatementExecuted(stmtId)) {
+ // Skip the incoming statement because it has already been logged locally
+ return lastResult;
+ }
+ } catch (const DBException& ex) {
+ // If the transaction chain was truncated on the recipient shard, then we are most likely
+ // copying from a session that hasn't been touched on the recipient shard for a very long
+ // time but could be recent on the donor.
+ //
+ // We continue copying regardless to get the entire transaction from the donor.
+ if (ex.code() != ErrorCodes::IncompleteTransactionHistory) {
+ throw;
+ }
+
+ if (stmtId == kIncompleteHistoryStmtId) {
+ // No need to log entries for transactions whose history has been truncated
+ return lastResult;
+ }
}
BSONObj object(result.isPrePostImage
diff --git a/src/mongo/db/s/session_catalog_migration_destination_test.cpp b/src/mongo/db/s/session_catalog_migration_destination_test.cpp
index ffc5cd400f1..e3d00084e90 100644
--- a/src/mongo/db/s/session_catalog_migration_destination_test.cpp
+++ b/src/mongo/db/s/session_catalog_migration_destination_test.cpp
@@ -199,7 +199,7 @@ public:
TxnNumber txnNumber,
StmtId stmtId) {
const auto txnParticipant = TransactionParticipant::get(session);
- auto oplog = txnParticipant->checkStatementExecuted(opCtx, txnNumber, stmtId);
+ auto oplog = txnParticipant->checkStatementExecuted(stmtId);
ASSERT_TRUE(oplog);
}
@@ -209,7 +209,7 @@ public:
StmtId stmtId,
const repl::OplogEntry& expectedOplog) {
const auto txnParticipant = TransactionParticipant::get(session);
- auto oplog = txnParticipant->checkStatementExecuted(opCtx, txnNumber, stmtId);
+ auto oplog = txnParticipant->checkStatementExecuted(stmtId);
ASSERT_TRUE(oplog);
checkOplogWithNestedOplog(expectedOplog, *oplog);
}
@@ -1572,7 +1572,7 @@ TEST_F(SessionCatalogMigrationDestinationTest, OplogEntriesWithIncompleteHistory
checkStatementExecuted(opCtx, session.get(), 2, 23, oplogEntries[0]);
checkStatementExecuted(opCtx, session.get(), 2, 5, oplogEntries[2]);
- ASSERT_THROWS(txnParticipant->checkStatementExecuted(opCtx, 2, 38), AssertionException);
+ ASSERT_THROWS(txnParticipant->checkStatementExecuted(38), AssertionException);
}
TEST_F(SessionCatalogMigrationDestinationTest,
diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp
index c2ef072d72a..01bc5424644 100644
--- a/src/mongo/db/session_catalog_mongod.cpp
+++ b/src/mongo/db/session_catalog_mongod.cpp
@@ -192,16 +192,15 @@ void MongoDSessionCatalog::invalidateSessions(OperationContext* opCtx,
MongoDOperationContextSession::MongoDOperationContextSession(OperationContext* opCtx)
: _operationContextSession(opCtx) {
- if (!opCtx->getClient()->isInDirectClient()) {
- const auto txnParticipant = TransactionParticipant::get(opCtx);
- txnParticipant->refreshFromStorageIfNeeded();
- }
+ invariant(!opCtx->getClient()->isInDirectClient());
+
+ const auto txnParticipant = TransactionParticipant::get(opCtx);
+ txnParticipant->refreshFromStorageIfNeeded();
}
MongoDOperationContextSession::~MongoDOperationContextSession() = default;
void MongoDOperationContextSession::checkIn(OperationContext* opCtx) {
-
if (auto txnParticipant = TransactionParticipant::get(opCtx)) {
txnParticipant->stashTransactionResources(opCtx);
}
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp
index 4345613469c..aa01c5e0aa2 100644
--- a/src/mongo/db/transaction_participant.cpp
+++ b/src/mongo/db/transaction_participant.cpp
@@ -691,8 +691,7 @@ void TransactionParticipant::unstashTransactionResources(OperationContext* opCtx
{
stdx::lock_guard<stdx::mutex> lg(_mutex);
- // Always check session's txnNumber and '_txnState', since they can be modified by session
- // kill and migration, which do not check out the session.
+ _checkValid(lg);
_checkIsActiveTransaction(lg, *opCtx->getTxnNumber(), false);
// If this is not a multi-document transaction, there is nothing to unstash.
@@ -1641,12 +1640,13 @@ void TransactionParticipant::onWriteOpCompletedOnPrimary(
Date_t lastStmtIdWriteDate,
boost::optional<DurableTxnStateEnum> txnState) {
invariant(opCtx->lockState()->inAWriteUnitOfWork());
+ invariant(txnNumber == _activeTxnNumber);
stdx::unique_lock<stdx::mutex> ul(_mutex);
// Sanity check that we don't double-execute statements
for (const auto stmtId : stmtIdsWritten) {
- const auto stmtOpTime = _checkStatementExecuted(ul, txnNumber, stmtId);
+ const auto stmtOpTime = _checkStatementExecuted(stmtId);
if (stmtOpTime) {
fassertOnRepeatedExecution(
_sessionId(), txnNumber, stmtId, *stmtOpTime, lastStmtIdWriteOpTime);
@@ -1665,39 +1665,13 @@ void TransactionParticipant::onWriteOpCompletedOnPrimary(
opCtx, txnNumber, std::move(stmtIdsWritten), lastStmtIdWriteOpTime);
}
-bool TransactionParticipant::onMigrateBeginOnPrimary(OperationContext* opCtx,
- TxnNumber txnNumber,
- StmtId stmtId) {
- beginOrContinue(txnNumber, boost::none, boost::none);
-
- try {
- if (checkStatementExecuted(opCtx, txnNumber, stmtId)) {
- return false;
- }
- } catch (const DBException& ex) {
- // If the transaction chain was truncated on the recipient shard, then we are most likely
- // copying from a session that hasn't been touched on the recipient shard for a very long
- // time but could be recent on the donor.
- //
- // We continue copying regardless to get the entire transaction from the donor.
- if (ex.code() != ErrorCodes::IncompleteTransactionHistory) {
- throw;
- }
-
- if (stmtId == kIncompleteHistoryStmtId) {
- return false;
- }
- }
-
- return true;
-}
-
void TransactionParticipant::onMigrateCompletedOnPrimary(OperationContext* opCtx,
TxnNumber txnNumber,
std::vector<StmtId> stmtIdsWritten,
const repl::OpTime& lastStmtIdWriteOpTime,
Date_t oplogLastStmtIdWriteDate) {
invariant(opCtx->lockState()->inAWriteUnitOfWork());
+ invariant(txnNumber == _activeTxnNumber);
stdx::unique_lock<stdx::mutex> ul(_mutex);
@@ -1805,18 +1779,15 @@ repl::OpTime TransactionParticipant::getLastWriteOpTime(TxnNumber txnNumber) con
}
boost::optional<repl::OplogEntry> TransactionParticipant::checkStatementExecuted(
- OperationContext* opCtx, TxnNumber txnNumber, StmtId stmtId) const {
- const auto stmtTimestamp = [&] {
- stdx::lock_guard<stdx::mutex> lg(_mutex);
- return _checkStatementExecuted(lg, txnNumber, stmtId);
- }();
+ StmtId stmtId) const {
+ const auto stmtTimestamp = _checkStatementExecuted(stmtId);
if (!stmtTimestamp)
return boost::none;
TransactionHistoryIterator txnIter(*stmtTimestamp);
while (txnIter.hasNext()) {
- const auto entry = txnIter.next(opCtx);
+ const auto entry = txnIter.next(_opCtx());
invariant(entry.getStatementId());
if (*entry.getStatementId() == stmtId)
return entry;
@@ -1825,10 +1796,8 @@ boost::optional<repl::OplogEntry> TransactionParticipant::checkStatementExecuted
MONGO_UNREACHABLE;
}
-bool TransactionParticipant::checkStatementExecutedNoOplogEntryFetch(TxnNumber txnNumber,
- StmtId stmtId) const {
- stdx::lock_guard<stdx::mutex> lg(_mutex);
- return bool(_checkStatementExecuted(lg, txnNumber, stmtId));
+bool TransactionParticipant::checkStatementExecutedNoOplogEntryFetch(StmtId stmtId) const {
+ return bool(_checkStatementExecuted(stmtId));
}
void TransactionParticipant::_checkValid(WithLock) const {
@@ -1849,16 +1818,13 @@ void TransactionParticipant::_checkIsActiveTransaction(WithLock, TxnNumber txnNu
txnNumber == _activeTxnNumber);
}
-boost::optional<repl::OpTime> TransactionParticipant::_checkStatementExecuted(WithLock wl,
- TxnNumber txnNumber,
- StmtId stmtId) const {
- _checkValid(wl);
- _checkIsActiveTransaction(wl, txnNumber);
+boost::optional<repl::OpTime> TransactionParticipant::_checkStatementExecuted(StmtId stmtId) const {
+ invariant(_isValid);
const auto it = _activeTxnCommittedStatements.find(stmtId);
if (it == _activeTxnCommittedStatements.end()) {
uassert(ErrorCodes::IncompleteTransactionHistory,
- str::stream() << "Incomplete history detected for transaction " << txnNumber
+ str::stream() << "Incomplete history detected for transaction " << _activeTxnNumber
<< " on session "
<< _sessionId(),
!_hasIncompleteHistory);
@@ -1867,7 +1833,7 @@ boost::optional<repl::OpTime> TransactionParticipant::_checkStatementExecuted(Wi
}
invariant(_lastWrittenSessionRecord);
- invariant(_lastWrittenSessionRecord->getTxnNum() == txnNumber);
+ invariant(_lastWrittenSessionRecord->getTxnNum() == _activeTxnNumber);
return it->second;
}
diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h
index 56461dedd0a..234e27f2b44 100644
--- a/src/mongo/db/transaction_participant.h
+++ b/src/mongo/db/transaction_participant.h
@@ -327,15 +327,6 @@ public:
boost::optional<DurableTxnStateEnum> txnState);
/**
- * Helper function to begin a migration on a primary node.
- *
- * Returns whether the specified statement should be migrated at all or skipped.
- *
- * Not called with session checked out.
- */
- bool onMigrateBeginOnPrimary(OperationContext* opCtx, TxnNumber txnNumber, StmtId stmtId);
-
- /**
* Called after an entry for the specified session and transaction has been written to the oplog
* during chunk migration, while the node is still primary. Must be called while the caller is
* still in the oplog write's WUOW. Updates the on-disk state of the session to match the
@@ -362,9 +353,7 @@ public:
*
* Throws if the session has been invalidated or the active transaction number doesn't match.
*/
- boost::optional<repl::OplogEntry> checkStatementExecuted(OperationContext* opCtx,
- TxnNumber txnNumber,
- StmtId stmtId) const;
+ boost::optional<repl::OplogEntry> checkStatementExecuted(StmtId stmtId) const;
/**
* Checks whether the given statementId for the specified transaction has already executed
@@ -374,7 +363,7 @@ public:
*
* Throws if the session has been invalidated or the active transaction number doesn't match.
*/
- bool checkStatementExecutedNoOplogEntryFetch(TxnNumber txnNumber, StmtId stmtId) const;
+ bool checkStatementExecutedNoOplogEntryFetch(StmtId stmtId) const;
/**
* Marks the session as requiring refresh. Used when the session state has been modified
@@ -653,9 +642,7 @@ private:
// a check that the caller operates on the transaction it thinks it is operating on.
void _checkIsActiveTransaction(WithLock, TxnNumber txnNumber) const;
- boost::optional<repl::OpTime> _checkStatementExecuted(WithLock,
- TxnNumber txnNumber,
- StmtId stmtId) const;
+ boost::optional<repl::OpTime> _checkStatementExecuted(StmtId stmtId) const;
UpdateRequest _makeUpdateRequest(WithLock,
TxnNumber newTxnNumber,
diff --git a/src/mongo/db/transaction_participant_retryable_writes_test.cpp b/src/mongo/db/transaction_participant_retryable_writes_test.cpp
index f3900a43b5f..638f931ef20 100644
--- a/src/mongo/db/transaction_participant_retryable_writes_test.cpp
+++ b/src/mongo/db/transaction_participant_retryable_writes_test.cpp
@@ -384,53 +384,40 @@ TEST_F(TransactionParticipantRetryableWritesTest, CheckStatementExecuted) {
const TxnNumber txnNum = 100;
txnParticipant->beginOrContinue(txnNum, boost::none, boost::none);
- ASSERT(!txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1000));
- ASSERT(!txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 1000));
+ ASSERT(!txnParticipant->checkStatementExecuted(1000));
+ ASSERT(!txnParticipant->checkStatementExecutedNoOplogEntryFetch(1000));
const auto firstOpTime = writeTxnRecord(txnNum, 1000, {}, boost::none);
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1000));
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 1000));
+ ASSERT(txnParticipant->checkStatementExecuted(1000));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(1000));
- ASSERT(!txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2000));
- ASSERT(!txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 2000));
+ ASSERT(!txnParticipant->checkStatementExecuted(2000));
+ ASSERT(!txnParticipant->checkStatementExecutedNoOplogEntryFetch(2000));
writeTxnRecord(txnNum, 2000, firstOpTime, boost::none);
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2000));
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 2000));
+ ASSERT(txnParticipant->checkStatementExecuted(2000));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(2000));
// Invalidate the session and ensure the statements still check out
txnParticipant->invalidate();
txnParticipant->refreshFromStorageIfNeeded();
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1000));
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2000));
+ ASSERT(txnParticipant->checkStatementExecuted(1000));
+ ASSERT(txnParticipant->checkStatementExecuted(2000));
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 1000));
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 2000));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(1000));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(2000));
}
-TEST_F(TransactionParticipantRetryableWritesTest, CheckStatementExecutedForOldTransactionThrows) {
- const auto txnParticipant = TransactionParticipant::get(opCtx());
- txnParticipant->refreshFromStorageIfNeeded();
-
- const TxnNumber txnNum = 100;
- txnParticipant->beginOrContinue(txnNum, boost::none, boost::none);
-
- ASSERT_THROWS_CODE(txnParticipant->checkStatementExecuted(opCtx(), txnNum - 1, 0),
- AssertionException,
- ErrorCodes::ConflictingOperationInProgress);
-}
-
-TEST_F(TransactionParticipantRetryableWritesTest,
- CheckStatementExecutedForInvalidatedTransactionThrows) {
+DEATH_TEST_F(TransactionParticipantRetryableWritesTest,
+ CheckStatementExecutedForInvalidatedTransactionInvariants,
+ "Invariant failure _isValid") {
const auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant->invalidate();
-
- ASSERT_THROWS_CODE(txnParticipant->checkStatementExecuted(opCtx(), 100, 0),
- AssertionException,
- ErrorCodes::ConflictingOperationInProgress);
+ txnParticipant->checkStatementExecuted(0);
}
-TEST_F(TransactionParticipantRetryableWritesTest,
- WriteOpCompletedOnPrimaryForOldTransactionThrows) {
+DEATH_TEST_F(TransactionParticipantRetryableWritesTest,
+ WriteOpCompletedOnPrimaryForOldTransactionInvariants,
+ "Invariant failure txnNumber == _activeTxnNumber") {
const auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant->refreshFromStorageIfNeeded();
@@ -453,15 +440,14 @@ TEST_F(TransactionParticipantRetryableWritesTest,
AutoGetCollection autoColl(opCtx(), kNss, MODE_IX);
WriteUnitOfWork wuow(opCtx());
const auto opTime = logOp(opCtx(), kNss, uuid, sessionId, txnNum - 1, 0);
- ASSERT_THROWS_CODE(txnParticipant->onWriteOpCompletedOnPrimary(
- opCtx(), txnNum - 1, {0}, opTime, Date_t::now(), boost::none),
- AssertionException,
- ErrorCodes::ConflictingOperationInProgress);
+ txnParticipant->onWriteOpCompletedOnPrimary(
+ opCtx(), txnNum - 1, {0}, opTime, Date_t::now(), boost::none);
}
}
-TEST_F(TransactionParticipantRetryableWritesTest,
- WriteOpCompletedOnPrimaryForInvalidatedTransactionThrows) {
+DEATH_TEST_F(TransactionParticipantRetryableWritesTest,
+ WriteOpCompletedOnPrimaryForInvalidatedTransactionInvariants,
+ "Invariant failure txnNumber == _activeTxnNumber") {
const auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant->refreshFromStorageIfNeeded();
@@ -474,11 +460,8 @@ TEST_F(TransactionParticipantRetryableWritesTest,
const auto opTime = logOp(opCtx(), kNss, uuid, *opCtx()->getLogicalSessionId(), txnNum, 0);
txnParticipant->invalidate();
-
- ASSERT_THROWS_CODE(txnParticipant->onWriteOpCompletedOnPrimary(
- opCtx(), txnNum, {0}, opTime, Date_t::now(), boost::none),
- AssertionException,
- ErrorCodes::ConflictingOperationInProgress);
+ txnParticipant->onWriteOpCompletedOnPrimary(
+ opCtx(), txnNum, {0}, opTime, Date_t::now(), boost::none);
}
TEST_F(TransactionParticipantRetryableWritesTest,
@@ -503,7 +486,7 @@ TEST_F(TransactionParticipantRetryableWritesTest,
}
txnParticipant->refreshFromStorageIfNeeded();
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 0));
+ ASSERT(txnParticipant->checkStatementExecuted(0));
}
TEST_F(TransactionParticipantRetryableWritesTest, IncompleteHistoryDueToOpLogTruncation) {
@@ -561,17 +544,17 @@ TEST_F(TransactionParticipantRetryableWritesTest, IncompleteHistoryDueToOpLogTru
const auto txnParticipant = TransactionParticipant::get(opCtx());
txnParticipant->refreshFromStorageIfNeeded();
- ASSERT_THROWS_CODE(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 0),
+ ASSERT_THROWS_CODE(txnParticipant->checkStatementExecuted(0),
AssertionException,
ErrorCodes::IncompleteTransactionHistory);
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1));
- ASSERT(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2));
+ ASSERT(txnParticipant->checkStatementExecuted(1));
+ ASSERT(txnParticipant->checkStatementExecuted(2));
- ASSERT_THROWS_CODE(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 0),
+ ASSERT_THROWS_CODE(txnParticipant->checkStatementExecutedNoOplogEntryFetch(0),
AssertionException,
ErrorCodes::IncompleteTransactionHistory);
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 1));
- ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(txnNum, 2));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(1));
+ ASSERT(txnParticipant->checkStatementExecutedNoOplogEntryFetch(2));
}
TEST_F(TransactionParticipantRetryableWritesTest, ErrorOnlyWhenStmtIdBeingCheckedIsNotInCache) {
@@ -642,24 +625,24 @@ TEST_F(TransactionParticipantRetryableWritesTest, ErrorOnlyWhenStmtIdBeingChecke
}
{
- auto oplog = txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1);
+ auto oplog = txnParticipant->checkStatementExecuted(1);
ASSERT_TRUE(oplog);
ASSERT_EQ(firstOpTime, oplog->getOpTime());
}
- ASSERT_THROWS(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2), AssertionException);
+ ASSERT_THROWS(txnParticipant->checkStatementExecuted(2), AssertionException);
// Should have the same behavior after loading state from storage.
txnParticipant->invalidate();
txnParticipant->refreshFromStorageIfNeeded();
{
- auto oplog = txnParticipant->checkStatementExecuted(opCtx(), txnNum, 1);
+ auto oplog = txnParticipant->checkStatementExecuted(1);
ASSERT_TRUE(oplog);
ASSERT_EQ(firstOpTime, oplog->getOpTime());
}
- ASSERT_THROWS(txnParticipant->checkStatementExecuted(opCtx(), txnNum, 2), AssertionException);
+ ASSERT_THROWS(txnParticipant->checkStatementExecuted(2), AssertionException);
}
} // namespace
diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp
index 773b5c42b5a..6bc19f98e03 100644
--- a/src/mongo/db/transaction_participant_test.cpp
+++ b/src/mongo/db/transaction_participant_test.cpp
@@ -1150,8 +1150,6 @@ TEST_F(TxnParticipantTest, StashInNestedSessionIsANoop) {
{
// Make it look like we're in a DBDirectClient running a nested operation.
DirectClientSetter inDirectClient(opCtx());
- MongoDOperationContextSession innerScopedSession(opCtx());
-
txnParticipant->stashTransactionResources(opCtx());
// The stash was a noop, so the locker, RecoveryUnit, and WriteUnitOfWork on the