summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjannaerin <golden.janna@gmail.com>2018-08-10 11:58:09 -0400
committerjannaerin <golden.janna@gmail.com>2018-08-13 15:14:46 -0400
commitd3941824b4473898bf987c7db381a84879d33c27 (patch)
treeea4edcf57f7913f1f32d5e865dd8e795f95c3d9e
parent3fc7971ea53270cccf5bf164862186e19de9a185 (diff)
downloadmongo-d3941824b4473898bf987c7db381a84879d33c27.tar.gz
SERVER-36565 Check if txn in progress or aborted when executing write commands
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp8
-rw-r--r--src/mongo/db/service_entry_point_common.cpp2
-rw-r--r--src/mongo/db/transaction_participant.h10
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
@@ -253,6 +253,16 @@ public:
}
/**
+ * 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<stdx::mutex> 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
* transaction is in progress.