summaryrefslogtreecommitdiff
path: root/src/mongo/db/s/transaction_coordinator_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/s/transaction_coordinator_util.cpp')
-rw-r--r--src/mongo/db/s/transaction_coordinator_util.cpp9
1 files changed, 9 insertions, 0 deletions
diff --git a/src/mongo/db/s/transaction_coordinator_util.cpp b/src/mongo/db/s/transaction_coordinator_util.cpp
index 6c71a3071cb..776ead96215 100644
--- a/src/mongo/db/s/transaction_coordinator_util.cpp
+++ b/src/mongo/db/s/transaction_coordinator_util.cpp
@@ -351,6 +351,15 @@ repl::OpTime persistDecisionBlocking(OperationContext* opCtx,
sessionInfo.setTxnRetryCounter(*txnNumberAndRetryCounter.getTxnRetryCounter());
}
+ // The transaction participant is already holding a global IX lock (and therefore an FCV IX
+ // lock) when we get to this point. Since the setFCV command takes an FCV S lock, we can hit a
+ // deadlock if the setFCV enqueues its lock after the transaction participant has already
+ // acquired its lock, but before we (the transaction coordinator) acquire ours. To remedy this,
+ // we choose to bypass this barrier that setFCV creates. This is safe because the setFCV command
+ // drains any outstanding cross-shard transactions before completing an FCV upgrade/downgrade.
+ // It does so by waiting for the participant portion of the cross-shard transaction to have
+ // released its FCV IX lock.
+ ShouldNotConflictWithSetFeatureCompatibilityVersionBlock noFCVLock{opCtx->lockState()};
DBDirectClient client(opCtx);
// Throws if serializing the request or deserializing the response fails.