From d3941824b4473898bf987c7db381a84879d33c27 Mon Sep 17 00:00:00 2001 From: jannaerin Date: Fri, 10 Aug 2018 11:58:09 -0400 Subject: SERVER-36565 Check if txn in progress or aborted when executing write commands --- src/mongo/db/ops/write_ops_exec.cpp | 8 ++++---- src/mongo/db/service_entry_point_common.cpp | 2 +- src/mongo/db/transaction_participant.h | 10 ++++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 85411e0106d..6e46309190b 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -229,7 +229,7 @@ bool handleError(OperationContext* opCtx, } auto txnParticipant = TransactionParticipant::get(opCtx); - if (txnParticipant && txnParticipant->inMultiDocumentTransaction()) { + if (txnParticipant && txnParticipant->inActiveOrKilledMultiDocumentTransaction()) { // If we are in a transaction, we must fail the whole batch. throw; } @@ -484,7 +484,7 @@ WriteResult performInserts(OperationContext* opCtx, // transaction. auto txnParticipant = TransactionParticipant::get(opCtx); invariant(!opCtx->lockState()->inAWriteUnitOfWork() || - (txnParticipant && txnParticipant->inMultiDocumentTransaction())); + (txnParticipant && txnParticipant->inActiveOrKilledMultiDocumentTransaction())); auto& curOp = *CurOp::get(opCtx); ON_BLOCK_EXIT([&] { // This is the only part of finishCurOp we need to do for inserts because they reuse the @@ -691,7 +691,7 @@ WriteResult performUpdates(OperationContext* opCtx, const write_ops::Update& who // transaction. auto txnParticipant = TransactionParticipant::get(opCtx); invariant(!opCtx->lockState()->inAWriteUnitOfWork() || - (txnParticipant && txnParticipant->inMultiDocumentTransaction())); + (txnParticipant && txnParticipant->inActiveOrKilledMultiDocumentTransaction())); uassertStatusOK(userAllowedWriteNS(wholeOp.getNamespace())); DisableDocumentValidationIfTrue docValidationDisabler( @@ -834,7 +834,7 @@ WriteResult performDeletes(OperationContext* opCtx, const write_ops::Delete& who // transaction. auto txnParticipant = TransactionParticipant::get(opCtx); invariant(!opCtx->lockState()->inAWriteUnitOfWork() || - (txnParticipant && txnParticipant->inMultiDocumentTransaction())); + (txnParticipant && txnParticipant->inActiveOrKilledMultiDocumentTransaction())); uassertStatusOK(userAllowedWriteNS(wholeOp.getNamespace())); DisableDocumentValidationIfTrue docValidationDisabler( diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 0b4f3dee5e9..3929cb7f795 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -831,7 +831,7 @@ void execCommandDatabase(OperationContext* opCtx, if (readConcernArgs.getLevel() == repl::ReadConcernLevel::kSnapshotReadConcern) { uassert(ErrorCodes::InvalidOptions, "readConcern level snapshot is only valid in multi-statement transactions", - txnParticipant && txnParticipant->inMultiDocumentTransaction()); + txnParticipant && txnParticipant->inActiveOrKilledMultiDocumentTransaction()); uassert(ErrorCodes::InvalidOptions, "readConcern level snapshot requires a session ID", opCtx->getLogicalSessionId()); diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h index 38fae7a0366..73f06148041 100644 --- a/src/mongo/db/transaction_participant.h +++ b/src/mongo/db/transaction_participant.h @@ -252,6 +252,16 @@ public: return _txnState.isAborted(lk); } + /** + * Returns true if we are in an active multi-document transaction or if the transaction has + * been aborted. This is used to cover the case where a transaction has been aborted, but the + * OperationContext state has not been cleared yet. + */ + bool inActiveOrKilledMultiDocumentTransaction() const { + stdx::lock_guard lk(_mutex); + return (_txnState.inMultiDocumentTransaction(lk) || _txnState.isAborted(lk)); + } + /** * Adds a stored operation to the list of stored operations for the current multi-document * (non-autocommit) transaction. It is illegal to add operations when no multi-document -- cgit v1.2.1