diff options
author | Suganthi Mani <suganthi.mani@mongodb.com> | 2019-07-12 16:11:52 -0400 |
---|---|---|
committer | Suganthi Mani <suganthi.mani@mongodb.com> | 2019-07-21 22:40:51 -0400 |
commit | a5d4ab967af9cbba17e6aa5afadca35927bd74c1 (patch) | |
tree | eab6ec805312a30b0a7e0d0392f40a8d0c421b1a /src/mongo/db/transaction_participant.cpp | |
parent | 0fddb3efeb0677b6be81fa3615a55d1f2888ed38 (diff) | |
download | mongo-a5d4ab967af9cbba17e6aa5afadca35927bd74c1.tar.gz |
SERVER-41980 Prepared transactions should not acquire ticket on primary.
Diffstat (limited to 'src/mongo/db/transaction_participant.cpp')
-rw-r--r-- | src/mongo/db/transaction_participant.cpp | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp index 54544c4d6e6..c9b54f19cb1 100644 --- a/src/mongo/db/transaction_participant.cpp +++ b/src/mongo/db/transaction_participant.cpp @@ -869,7 +869,7 @@ void TransactionParticipant::Participant::resetRetryableWriteState(OperationCont } void TransactionParticipant::Participant::_releaseTransactionResourcesToOpCtx( - OperationContext* opCtx, MaxLockTimeout maxLockTimeout) { + OperationContext* opCtx, MaxLockTimeout maxLockTimeout, AcquireTicket acquireTicket) { // Transaction resources already exist for this transaction. Transfer them from the // stash to the operation context. // @@ -910,8 +910,14 @@ void TransactionParticipant::Participant::_releaseTransactionResourcesToOpCtx( } } + if (acquireTicket == AcquireTicket::kSkip) { + stashLocker->skipAcquireTicket(); + } + tempTxnResourceStash->release(opCtx); releaseOnError.dismiss(); + + invariant(opCtx->lockState()->shouldAcquireTicket() || o().txnState.isPrepared()); } void TransactionParticipant::Participant::unstashTransactionResources(OperationContext* opCtx, @@ -928,13 +934,26 @@ void TransactionParticipant::Participant::unstashTransactionResources(OperationC _checkIsCommandValidWithTxnState(*opCtx->getTxnNumber(), cmdName); if (o().txnResourceStash) { MaxLockTimeout maxLockTimeout; - // Max lock timeout must not be set on secondaries, since secondary oplog application cannot - // fail. And, primaries should respect the transaction lock timeout, since it can prevent - // the transaction from making progress. - maxLockTimeout = - opCtx->writesAreReplicated() ? MaxLockTimeout::kAllowed : MaxLockTimeout::kNotAllowed; + // Default is we should acquire ticket. + AcquireTicket acquireTicket{AcquireTicket::kNoSkip}; + + if (opCtx->writesAreReplicated()) { + // Primaries should respect the transaction lock timeout, since it can prevent + // the transaction from making progress. + maxLockTimeout = MaxLockTimeout::kAllowed; + // Prepared transactions should not acquire ticket. Else, it can deadlock with other + // non-transactional operations that have exhausted the write tickets and are blocked on + // them due to prepare or lock conflict. + if (o().txnState.isPrepared()) { + acquireTicket = AcquireTicket::kSkip; + } + } else { + // Max lock timeout must not be set on secondaries, since secondary oplog application + // cannot fail. + maxLockTimeout = MaxLockTimeout::kNotAllowed; + } - _releaseTransactionResourcesToOpCtx(opCtx, maxLockTimeout); + _releaseTransactionResourcesToOpCtx(opCtx, maxLockTimeout, acquireTicket); stdx::lock_guard<Client> lg(*opCtx->getClient()); o(lg).transactionMetricsObserver.onUnstash(ServerTransactionsMetrics::get(opCtx), opCtx->getServiceContext()->getTickSource()); @@ -1013,7 +1032,7 @@ void TransactionParticipant::Participant::refreshLocksForPreparedTransaction( // Lock and Ticket reacquisition of a prepared transaction should not fail for // state transitions (step up/step down). - _releaseTransactionResourcesToOpCtx(opCtx, MaxLockTimeout::kNotAllowed); + _releaseTransactionResourcesToOpCtx(opCtx, MaxLockTimeout::kNotAllowed, AcquireTicket::kNoSkip); // Snapshot transactions don't conflict with PBWM lock on both primary and secondary. invariant(!opCtx->lockState()->shouldConflictWithSecondaryBatchApplication()); |