diff options
author | Jason Zhang <jason.zhang@mongodb.com> | 2022-02-03 16:02:58 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-02-03 17:13:45 +0000 |
commit | 0e4e2c4a28fee3358ff2f0f0f102f0e8b59185d0 (patch) | |
tree | 847a267aa8f93f167bd8d52da2078e35ab4a670b /src | |
parent | 882ebf1ad73b1c39af8b0cd82de7c648b8a860d2 (diff) | |
download | mongo-0e4e2c4a28fee3358ff2f0f0f102f0e8b59185d0.tar.gz |
SERVER-61088 Make transaction participants check if txnRetryCounter is supported during startTransaction and have mongos use it
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/base/error_codes.yml | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/txn_cmds.idl | 1 | ||||
-rw-r--r-- | src/mongo/db/error_labels.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/initialize_operation_session_info.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/op_observer_impl.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/s/transaction_coordinator_service.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/s/transaction_coordinator_test.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/s/transaction_coordinator_util.cpp | 33 | ||||
-rw-r--r-- | src/mongo/db/transaction_participant.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/transaction_participant_test.cpp | 45 | ||||
-rw-r--r-- | src/mongo/s/transaction_router.cpp | 7 | ||||
-rw-r--r-- | src/mongo/s/transaction_router_test.cpp | 86 |
12 files changed, 151 insertions, 87 deletions
diff --git a/src/mongo/base/error_codes.yml b/src/mongo/base/error_codes.yml index 8cfd049fb92..0a8b08802cd 100644 --- a/src/mongo/base/error_codes.yml +++ b/src/mongo/base/error_codes.yml @@ -467,6 +467,8 @@ error_codes: - {code: 363, name: RetryableTransactionInProgress} + - {code: 364, name: TxnRetryCounterNotSupported} + # Error codes 4000-8999 are reserved. # Non-sequential error codes for compatibility only) diff --git a/src/mongo/db/commands/txn_cmds.idl b/src/mongo/db/commands/txn_cmds.idl index 61cc3afa783..626d61c75d7 100644 --- a/src/mongo/db/commands/txn_cmds.idl +++ b/src/mongo/db/commands/txn_cmds.idl @@ -43,7 +43,6 @@ structs: write for it" type: bool - TxnRecoveryToken: description: "Contains info for retrying the commit of a sharded transaction" fields: diff --git a/src/mongo/db/error_labels.cpp b/src/mongo/db/error_labels.cpp index ecb1e499168..b66d0df2d74 100644 --- a/src/mongo/db/error_labels.cpp +++ b/src/mongo/db/error_labels.cpp @@ -199,6 +199,8 @@ bool isTransientTransactionError(ErrorCodes::Error code, case ErrorCodes::StaleDbVersion: case ErrorCodes::TenantMigrationAborted: case ErrorCodes::TenantMigrationCommitted: + // TODO: (SERVER-62375): Remove upgrade/downgrade code for internal transactions + case ErrorCodes::TxnRetryCounterNotSupported: return true; default: isTransient = false; diff --git a/src/mongo/db/initialize_operation_session_info.cpp b/src/mongo/db/initialize_operation_session_info.cpp index 659d429ef7f..4750869478f 100644 --- a/src/mongo/db/initialize_operation_session_info.cpp +++ b/src/mongo/db/initialize_operation_session_info.cpp @@ -135,10 +135,6 @@ OperationSessionInfoFromClient initializeOperationSessionInfo(OperationContext* if (auto txnRetryCounter = osi.getTxnRetryCounter()) { uassert(ErrorCodes::InvalidOptions, - "txnRetryCounter is not enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); - uassert(ErrorCodes::InvalidOptions, "txnRetryCounter is only allowed for internal clients", isAuthorizedForInternalClusterAction); uassert(ErrorCodes::InvalidOptions, diff --git a/src/mongo/db/op_observer_impl.cpp b/src/mongo/db/op_observer_impl.cpp index 08cf284929c..895845a0fde 100644 --- a/src/mongo/db/op_observer_impl.cpp +++ b/src/mongo/db/op_observer_impl.cpp @@ -1346,16 +1346,13 @@ OpTimeBundle logApplyOpsForTransaction(OperationContext* opCtx, invariant(isInternalSessionForRetryableWrite(*opCtx->getLogicalSessionId())); } - const bool areInternalTransactionsEnabled = - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility); const auto txnRetryCounter = *opCtx->getTxnRetryCounter(); oplogEntry->setOpType(repl::OpTypeEnum::kCommand); oplogEntry->setNss({"admin", "$cmd"}); oplogEntry->setSessionId(opCtx->getLogicalSessionId()); oplogEntry->setTxnNumber(opCtx->getTxnNumber()); - if (areInternalTransactionsEnabled && !isDefaultTxnRetryCounter(txnRetryCounter)) { + if (!isDefaultTxnRetryCounter(txnRetryCounter)) { oplogEntry->getOperationSessionInfo().setTxnRetryCounter(txnRetryCounter); } @@ -1369,7 +1366,7 @@ OpTimeBundle logApplyOpsForTransaction(OperationContext* opCtx, sessionTxnRecord.setLastWriteDate(times.wallClockTime); sessionTxnRecord.setState(txnState); sessionTxnRecord.setStartOpTime(startOpTime); - if (areInternalTransactionsEnabled && !isDefaultTxnRetryCounter(txnRetryCounter)) { + if (!isDefaultTxnRetryCounter(txnRetryCounter)) { sessionTxnRecord.setTxnRetryCounter(txnRetryCounter); } onWriteOpCompleted(opCtx, std::move(stmtIdsWritten), sessionTxnRecord); @@ -1587,16 +1584,13 @@ int logOplogEntriesForTransaction( void logCommitOrAbortForPreparedTransaction(OperationContext* opCtx, MutableOplogEntry* oplogEntry, DurableTxnStateEnum durableState) { - const bool areInternalTransactionsEnabled = - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility); const auto txnRetryCounter = *opCtx->getTxnRetryCounter(); oplogEntry->setOpType(repl::OpTypeEnum::kCommand); oplogEntry->setNss({"admin", "$cmd"}); oplogEntry->setSessionId(opCtx->getLogicalSessionId()); oplogEntry->setTxnNumber(opCtx->getTxnNumber()); - if (areInternalTransactionsEnabled && !isDefaultTxnRetryCounter(txnRetryCounter)) { + if (!isDefaultTxnRetryCounter(txnRetryCounter)) { oplogEntry->getOperationSessionInfo().setTxnRetryCounter(txnRetryCounter); } oplogEntry->setPrevWriteOpTimeInTransaction( @@ -1624,7 +1618,7 @@ void logCommitOrAbortForPreparedTransaction(OperationContext* opCtx, sessionTxnRecord.setLastWriteOpTime(oplogOpTime); sessionTxnRecord.setLastWriteDate(oplogEntry->getWallClockTime()); sessionTxnRecord.setState(durableState); - if (areInternalTransactionsEnabled && !isDefaultTxnRetryCounter(txnRetryCounter)) { + if (!isDefaultTxnRetryCounter(txnRetryCounter)) { sessionTxnRecord.setTxnRetryCounter(txnRetryCounter); } onWriteOpCompleted(opCtx, {}, sessionTxnRecord); diff --git a/src/mongo/db/s/transaction_coordinator_service.cpp b/src/mongo/db/s/transaction_coordinator_service.cpp index 7deb69f13d4..bdc4cc373d9 100644 --- a/src/mongo/db/s/transaction_coordinator_service.cpp +++ b/src/mongo/db/s/transaction_coordinator_service.cpp @@ -243,11 +243,6 @@ void TransactionCoordinatorService::onStepUp(OperationContext* opCtx, const auto txnNumber = *doc.getId().getTxnNumber(); const auto txnRetryCounter = [&] { if (auto optTxnRetryCounter = doc.getId().getTxnRetryCounter()) { - uassert(ErrorCodes::InvalidOptions, - "TxnRetryCounter is only supported when internal " - "transactions are enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); return *optTxnRetryCounter; } return 0; diff --git a/src/mongo/db/s/transaction_coordinator_test.cpp b/src/mongo/db/s/transaction_coordinator_test.cpp index 2d1187bc215..f650004e3b8 100644 --- a/src/mongo/db/s/transaction_coordinator_test.cpp +++ b/src/mongo/db/s/transaction_coordinator_test.cpp @@ -640,7 +640,7 @@ TEST_F(TransactionCoordinatorDriverTest, } TEST_F(TransactionCoordinatorDriverTest, - SendPrepareAndDecisionDoesNotAttachTxnRetryCounterIfFeatureFlagIsNotEnabled) { + SendPrepareAndDecisionContinuesToUseTxnRetryCounterIfNotDefault) { RAIIServerParameterControllerForTest controller{"featureFlagInternalTransactions", false}; txn::AsyncWorkScheduler aws(getServiceContext()); auto prepareFuture = txn::sendPrepare(getServiceContext(), @@ -650,7 +650,9 @@ TEST_F(TransactionCoordinatorDriverTest, APIParameters(), kOneShardIdList); onCommands({[&](const executor::RemoteCommandRequest& request) { - ASSERT_FALSE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_TRUE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_EQUALS(request.cmdObj.getIntField("txnRetryCounter"), + *_txnNumberAndRetryCounter.getTxnRetryCounter()); return kNoSuchTransaction; }}); prepareFuture.get(); @@ -663,7 +665,9 @@ TEST_F(TransactionCoordinatorDriverTest, kOneShardIdList, {}); onCommands({[&](const executor::RemoteCommandRequest& request) { - ASSERT_FALSE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_TRUE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_EQUALS(request.cmdObj.getIntField("txnRetryCounter"), + *_txnNumberAndRetryCounter.getTxnRetryCounter()); return kNoSuchTransaction; }}); commitFuture.get(); @@ -675,7 +679,9 @@ TEST_F(TransactionCoordinatorDriverTest, APIParameters(), kOneShardIdList); onCommands({[&](const executor::RemoteCommandRequest& request) { - ASSERT_FALSE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_TRUE(request.cmdObj.hasField("txnRetryCounter")); + ASSERT_EQUALS(request.cmdObj.getIntField("txnRetryCounter"), + *_txnNumberAndRetryCounter.getTxnRetryCounter()); return kNoSuchTransaction; }}); abortFuture.get(); diff --git a/src/mongo/db/s/transaction_coordinator_util.cpp b/src/mongo/db/s/transaction_coordinator_util.cpp index 26e7039c8d6..6c71a3071cb 100644 --- a/src/mongo/db/s/transaction_coordinator_util.cpp +++ b/src/mongo/db/s/transaction_coordinator_util.cpp @@ -126,10 +126,6 @@ repl::OpTime persistParticipantListBlocking( sessionInfo.setTxnNumber(txnNumberAndRetryCounter.getTxnNumber()); if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { - uassert(ErrorCodes::InvalidOptions, - "TxnRetryCounter is only supported when internal transactions are enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); sessionInfo.setTxnRetryCounter(*txnNumberAndRetryCounter.getTxnRetryCounter()); } @@ -258,10 +254,9 @@ Future<PrepareVoteConsensus> sendPrepare(ServiceContext* service, << txnNumberAndRetryCounter.getTxnNumber() << "autocommit" << false << WriteConcernOptions::kWriteConcernField << WriteConcernOptions::Majority)); - if (feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)) { - bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, - *txnNumberAndRetryCounter.getTxnRetryCounter()); + if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); + txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { + bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, *txnRetryCounter); } apiParams.appendInfo(&bob); auto prepareObj = prepareTransaction.toBSON(bob.obj()); @@ -353,10 +348,6 @@ repl::OpTime persistDecisionBlocking(OperationContext* opCtx, sessionInfo.setTxnNumber(txnNumberAndRetryCounter.getTxnNumber()); if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { - uassert(ErrorCodes::InvalidOptions, - "TxnRetryCounter is only supported when internal transactions are enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); sessionInfo.setTxnRetryCounter(*txnNumberAndRetryCounter.getTxnRetryCounter()); } @@ -469,10 +460,9 @@ Future<void> sendCommit(ServiceContext* service, << txnNumberAndRetryCounter.getTxnNumber() << "autocommit" << false << WriteConcernOptions::kWriteConcernField << WriteConcernOptions::Majority)); - if (feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)) { - bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, - *txnNumberAndRetryCounter.getTxnRetryCounter()); + if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); + txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { + bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, *txnRetryCounter); } apiParams.appendInfo(&bob); auto commitObj = commitTransaction.toBSON(bob.obj()); @@ -514,10 +504,9 @@ Future<void> sendAbort(ServiceContext* service, << txnNumberAndRetryCounter.getTxnNumber() << "autocommit" << false << WriteConcernOptions::kWriteConcernField << WriteConcernOptions::Majority)); - if (feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)) { - bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, - *txnNumberAndRetryCounter.getTxnRetryCounter()); + if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); + txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { + bob.append(OperationSessionInfo::kTxnRetryCounterFieldName, *txnRetryCounter); } apiParams.appendInfo(&bob); auto abortObj = abortTransaction.toBSON(bob.obj()); @@ -568,10 +557,6 @@ void deleteCoordinatorDocBlocking(OperationContext* opCtx, sessionInfo.setTxnNumber(txnNumberAndRetryCounter.getTxnNumber()); if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { - uassert(ErrorCodes::InvalidOptions, - "TxnRetryCounter is only supported when internal transactions are enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); sessionInfo.setTxnRetryCounter(*txnNumberAndRetryCounter.getTxnRetryCounter()); } diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp index d864b9e8a1c..dac6f597f7b 100644 --- a/src/mongo/db/transaction_participant.cpp +++ b/src/mongo/db/transaction_participant.cpp @@ -860,11 +860,21 @@ void TransactionParticipant::Participant::beginOrContinue( TxnNumberAndRetryCounter txnNumberAndRetryCounter, boost::optional<bool> autocommit, boost::optional<bool> startTransaction) { - if (_isInternalSession() && startTransaction) { - uassert(ErrorCodes::InternalTransactionNotSupported, - "Internal transactions are not enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); + if (startTransaction) { + if (_isInternalSession()) { + uassert(ErrorCodes::InternalTransactionNotSupported, + "Internal transactions are not enabled", + feature_flags::gFeatureFlagInternalTransactions.isEnabled( + serverGlobalParams.featureCompatibility)); + } + if (auto txnRetryCounter = txnNumberAndRetryCounter.getTxnRetryCounter(); + txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { + // TODO: (SERVER-62375): Remove upgrade/downgrade code for internal transactions + uassert(ErrorCodes::TxnRetryCounterNotSupported, + "TxnRetryCounter support is not enabled", + feature_flags::gFeatureFlagInternalTransactions.isEnabled( + serverGlobalParams.featureCompatibility)); + } } if (_isInternalSessionForRetryableWrite()) { @@ -2709,11 +2719,6 @@ void TransactionParticipant::Participant::_refreshSelfFromStorageIfNeeded(Operat o(lg).activeTxnNumberAndRetryCounter.setTxnRetryCounter([&] { if (lastTxnRecord->getState()) { if (lastTxnRecord->getTxnRetryCounter().has_value()) { - uassert( - ErrorCodes::InvalidOptions, - "TxnRetryCounter is only supported when internal transactions are enabled", - feature_flags::gFeatureFlagInternalTransactions.isEnabled( - serverGlobalParams.featureCompatibility)); return *lastTxnRecord->getTxnRetryCounter(); } return 0; diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp index dfcac1a329c..6d2df9f6ec5 100644 --- a/src/mongo/db/transaction_participant_test.cpp +++ b/src/mongo/db/transaction_participant_test.cpp @@ -5147,5 +5147,50 @@ TEST_F(ShardTxnParticipantTest, CannotModifyParentLsidOfNonChildSession) { } } +TEST_F(TxnParticipantTest, + ThrowIfTxnRetryCounterIsSpecifiedOnStartTransactionWithFeatureFlagDisabled) { + MongoDOperationContextSession opCtxSession(opCtx()); + auto txnParticipant = TransactionParticipant::get(opCtx()); + ASSERT_THROWS_CODE(txnParticipant.beginOrContinue(opCtx(), + {*opCtx()->getTxnNumber(), 1}, + false /* autocommit */, + true /* startTransaction */), + AssertionException, + ErrorCodes::TxnRetryCounterNotSupported); +} + +TEST_F(ShardTxnParticipantTest, + TxnRetryCounterShouldNotThrowIfWeContinueATransactionAfterDisablingFeatureFlag) { + // We swap in a new opCtx in order to set a new active txnRetryCounter for this test. + auto newClientOwned = getServiceContext()->makeClient("newClient"); + AlternativeClientRegion acr(newClientOwned); + auto newOpCtx = cc().makeOperationContext(); + + const auto newSessionId = makeLogicalSessionIdForTest(); + + newOpCtx.get()->setLogicalSessionId(newSessionId); + newOpCtx.get()->setTxnNumber(20); + newOpCtx.get()->setTxnRetryCounter(1); + newOpCtx.get()->setInMultiDocumentTransaction(); + MongoDOperationContextSession newOpCtxSession(newOpCtx.get()); + auto txnParticipant = TransactionParticipant::get(newOpCtx.get()); + + txnParticipant.beginOrContinue(newOpCtx.get(), + {*newOpCtx.get()->getTxnNumber(), 1}, + false /* autocommit */, + true /* startTransaction */); + + // We need to unstash and stash transaction resources so that we can continue the transaction in + // the following statements. + txnParticipant.unstashTransactionResources(newOpCtx.get(), "insert"); + txnParticipant.stashTransactionResources(newOpCtx.get()); + + RAIIServerParameterControllerForTest controller{"featureFlagInternalTransactions", false}; + + txnParticipant.beginOrContinue(newOpCtx.get(), + {*newOpCtx.get()->getTxnNumber(), 1}, + false /* autocommit */, + boost::none /* startTransaction */); +} } // namespace } // namespace mongo diff --git a/src/mongo/s/transaction_router.cpp b/src/mongo/s/transaction_router.cpp index fc9b2da5255..578d979b10c 100644 --- a/src/mongo/s/transaction_router.cpp +++ b/src/mongo/s/transaction_router.cpp @@ -475,8 +475,11 @@ BSONObj TransactionRouter::Participant::attachTxnFieldsIfNeeded( if (feature_flags::gFeatureFlagInternalTransactions.isEnabled( serverGlobalParams.featureCompatibility)) { - newCmd.append(OperationSessionInfoFromClient::kTxnRetryCounterFieldName, - *sharedOptions.txnNumberAndRetryCounter.getTxnRetryCounter()); + if (auto txnRetryCounter = sharedOptions.txnNumberAndRetryCounter.getTxnRetryCounter(); + txnRetryCounter && !isDefaultTxnRetryCounter(*txnRetryCounter)) { + newCmd.append(OperationSessionInfoFromClient::kTxnRetryCounterFieldName, + *sharedOptions.txnNumberAndRetryCounter.getTxnRetryCounter()); + } } return newCmd.obj(); diff --git a/src/mongo/s/transaction_router_test.cpp b/src/mongo/s/transaction_router_test.cpp index 6d27a481839..f0d0ab36264 100644 --- a/src/mongo/s/transaction_router_test.cpp +++ b/src/mongo/s/transaction_router_test.cpp @@ -247,8 +247,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0); + << "autocommit" << false << "txnNumber" << txnNum); { auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), @@ -266,7 +265,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, ASSERT_BSONOBJ_EQ(BSON("update" << "test" << "coordinator" << true << "autocommit" << false << "txnNumber" - << txnNum << "txnRetryCounter" << 0), + << txnNum), newCmd); } } @@ -287,8 +286,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, BasicStartTxnWithAtClusterTime) << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0); + << "autocommit" << false << "txnNumber" << txnNum); { auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), @@ -306,7 +304,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, BasicStartTxnWithAtClusterTime) ASSERT_BSONOBJ_EQ(BSON("update" << "test" << "coordinator" << true << "autocommit" << false << "txnNumber" - << txnNum << "txnRetryCounter" << 0), + << txnNum), newCmd); } } @@ -339,8 +337,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, NewParticipantMustAttachTxnAndRe << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0); + << "autocommit" << false << "txnNumber" << txnNum); { auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), @@ -358,7 +355,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, NewParticipantMustAttachTxnAndRe ASSERT_BSONOBJ_EQ(BSON("update" << "test" << "coordinator" << true << "autocommit" << false << "txnNumber" - << txnNum << "txnRetryCounter" << 0), + << txnNum), newCmd); } @@ -369,7 +366,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, NewParticipantMustAttachTxnAndRe << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "autocommit" << false << "txnNumber" - << txnNum << "txnRetryCounter" << 0); + << txnNum); { auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), @@ -386,8 +383,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, NewParticipantMustAttachTxnAndRe << "test")); ASSERT_BSONOBJ_EQ(BSON("update" << "test" - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0), + << "autocommit" << false << "txnNumber" << txnNum), newCmd); } } @@ -413,8 +409,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, StartingNewTxnShouldClearState) << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0), + << "autocommit" << false << "txnNumber" << txnNum), newCmd); } @@ -431,8 +426,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, StartingNewTxnShouldClearState) << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum2 - << "txnRetryCounter" << 0); + << "autocommit" << false << "txnNumber" << txnNum2); { auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), @@ -454,6 +448,46 @@ DEATH_TEST_F(TransactionRouterTestWithDefaultSession, TransactionRouter::TransactionActions::kStart); } +TEST_F(TransactionRouterTestWithDefaultSession, + DoNotAttachTxnRetryCounterIfTxnRetryCounterIsDefault) { + TxnNumber txnNum{3}; + + auto txnRouter = TransactionRouter::get(operationContext()); + txnRouter.beginOrContinueTxn(operationContext(), + TxnNumberAndRetryCounter(txnNum, 0), + TransactionRouter::TransactionActions::kStart); + txnRouter.setDefaultAtClusterTime(operationContext()); + txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, {}); + txnRouter.processParticipantResponse(operationContext(), shard1, kOkReadOnlyFalseResponse); + + auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), + shard1, + BSON("insert" + << "test" + << "txnNumber" << txnNum)); + ASSERT_EQ(newCmd.hasField("txnRetryCounter"), false); +} + +TEST_F(TransactionRouterTestWithDefaultSession, + AttachTxnRetryCounterIfTxnRetryCounterIsNotDefault) { + TxnNumber txnNum{3}; + + auto txnRouter = TransactionRouter::get(operationContext()); + txnRouter.beginOrContinueTxn(operationContext(), + TxnNumberAndRetryCounter(txnNum, 1), + TransactionRouter::TransactionActions::kStart); + txnRouter.setDefaultAtClusterTime(operationContext()); + txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, {}); + txnRouter.processParticipantResponse(operationContext(), shard1, kOkReadOnlyFalseResponse); + + auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), + shard1, + BSON("insert" + << "test" + << "txnNumber" << txnNum)); + ASSERT_EQ(newCmd.hasField("txnRetryCounter"), true); +} + TEST_F(TransactionRouterTestWithDefaultSession, NotAttachTxnRetryCounterIfFeatureFlagIsNotEnabled) { RAIIServerParameterControllerForTest controller{"featureFlagInternalTransactions", false}; @@ -498,7 +532,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, TxnNumberAndRetryCounter(txnNum, 0), TransactionRouter::TransactionActions::kStart); txnRouter.setDefaultAtClusterTime(operationContext()); - ASSERT_BSONOBJ_EQ(expectedCmd.addFields(BSON("txnRetryCounter" << 0)), + ASSERT_BSONOBJ_EQ(expectedCmd, txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, BSON("insert" @@ -532,7 +566,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, TxnNumberAndRetryCounter(txnNum, 0), TransactionRouter::TransactionActions::kStart); txnRouter.setDefaultAtClusterTime(operationContext()); - ASSERT_BSONOBJ_EQ(expectedCmd.addFields(BSON("txnRetryCounter" << 0)), + ASSERT_BSONOBJ_EQ(expectedCmd, txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, BSON("insert" @@ -1042,7 +1076,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, DoesNotAttachTxnNumIfAlreadyTher << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnRetryCounter" << 0); + << "autocommit" << false); auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, @@ -1094,8 +1128,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, AttachTxnValidatesReadConcernIfA << "snapshot" << "atClusterTime" << kInMemoryLogicalTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0), + << "autocommit" << false << "txnNumber" << txnNum), newCmd); } } @@ -1197,7 +1230,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, PassesThroughEmptyReadConcernToP << "test" << "readConcern" << BSONObj() << "startTransaction" << true << "coordinator" << true << "autocommit" << false << "txnNumber" - << txnNum << "txnRetryCounter" << 0); + << txnNum); auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, @@ -1225,8 +1258,7 @@ TEST_F(TransactionRouterTestWithDefaultSession, << "readConcern" << BSON("afterClusterTime" << kAfterClusterTime.asTimestamp()) << "startTransaction" << true << "coordinator" << true - << "autocommit" << false << "txnNumber" << txnNum - << "txnRetryCounter" << 0); + << "autocommit" << false << "txnNumber" << txnNum); auto newCmd = txnRouter.attachTxnFieldsIfNeeded(operationContext(), shard1, @@ -1310,8 +1342,9 @@ void checkSessionDetails(const BSONObj& cmdObj, ASSERT(osi.getAutocommit()); ASSERT_FALSE(*osi.getAutocommit()); - ASSERT(osi.getTxnRetryCounter()); - ASSERT_EQ(txnRetryCounter, *osi.getTxnRetryCounter()); + if (osi.getTxnRetryCounter()) { + ASSERT_EQ(txnRetryCounter, *osi.getTxnRetryCounter()); + } if (isCoordinator) { ASSERT_EQ(*isCoordinator, cmdObj["coordinator"].trueValue()); @@ -5639,6 +5672,5 @@ TEST_F(TransactionRouterMetricsTest, IsTrackingOverIfTxnImplicitlyAborted) { implicitAbortInProgress(); ASSERT(txnRouter().isTrackingOver()); } - } // unnamed namespace } // namespace mongo |