summaryrefslogtreecommitdiff
path: root/src/mongo/db/transaction_participant_test.cpp
diff options
context:
space:
mode:
authorEsha Maharishi <esha.maharishi@mongodb.com>2019-04-29 15:54:20 -0400
committerEsha Maharishi <esha.maharishi@mongodb.com>2019-05-02 14:54:20 -0400
commit2d54db5b603d8ac3d4529f773614db36ab1298e6 (patch)
treeba012bb80543ae4352664f55e891317bbd949eda /src/mongo/db/transaction_participant_test.cpp
parente85431e9c1cecb8d6eafee706b46c30c1aaa24d3 (diff)
downloadmongo-2d54db5b603d8ac3d4529f773614db36ab1298e6.tar.gz
SERVER-40808 Recovering a transaction's outcome should block if the participant is in prepare
Diffstat (limited to 'src/mongo/db/transaction_participant_test.cpp')
-rw-r--r--src/mongo/db/transaction_participant_test.cpp77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/mongo/db/transaction_participant_test.cpp b/src/mongo/db/transaction_participant_test.cpp
index 83eeba96415..00d04754702 100644
--- a/src/mongo/db/transaction_participant_test.cpp
+++ b/src/mongo/db/transaction_participant_test.cpp
@@ -3711,5 +3711,82 @@ TEST_F(TxnParticipantTest, OldestActiveTransactionTimestampTimeout) {
ASSERT_TRUE(ErrorCodes::isInterruption(statusWith.getStatus().code()));
};
+TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnAbortAfterPrepare) {
+ 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.abortActiveTransaction(opCtx());
+ ASSERT_TRUE(exitPrepareFuture.isReady());
+
+ // Once the promise has been fulfilled, new callers of onExitPrepare should immediately be
+ // ready.
+ ASSERT_TRUE(txnParticipant.onExitPrepare().isReady());
+
+ // abortTransaction is retryable, but does not cause the completion promise to be set again.
+ txnParticipant.abortActiveTransaction(opCtx());
+}
+
+TEST_F(TxnParticipantTest, ExitPreparePromiseIsFulfilledOnCommitAfterPrepare) {
+ 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);
+ const auto prepareTimestamp = txnParticipant.prepareTransaction(opCtx(), prepareOpTime);
+ const auto exitPrepareFuture = txnParticipant.onExitPrepare();
+ ASSERT_FALSE(exitPrepareFuture.isReady());
+
+ const auto commitTimestamp =
+ Timestamp(prepareTimestamp.getSecs(), prepareTimestamp.getInc() + 1);
+ txnParticipant.commitPreparedTransaction(opCtx(), commitTimestamp, {});
+ ASSERT_TRUE(exitPrepareFuture.isReady());
+
+ // Once the promise has been fulfilled, new callers of onExitPrepare should immediately be
+ // ready.
+ 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