summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiyuan Zhou <siyuan.zhou@mongodb.com>2018-10-12 18:38:16 -0400
committerSiyuan Zhou <siyuan.zhou@mongodb.com>2018-10-23 13:30:22 -0400
commitf48fed6054f6e2bb0a7c15b15256feb1eb175509 (patch)
tree02c77fc221353c2f8d20db4dd8ef06a178822919
parentdf048e23d9149a3607205ae0e69ef11e881c037c (diff)
downloadmongo-f48fed6054f6e2bb0a7c15b15256feb1eb175509.tar.gz
SERVER-37622 Disallow implicit abort on committed transactions.
-rw-r--r--buildscripts/resmokeconfig/suites/sharded_core_txns.yml2
-rw-r--r--jstests/core/txns/errors_on_committed_transaction.js (renamed from jstests/core/txns/prepare_committed_transaction.js)31
-rw-r--r--src/mongo/db/transaction_participant.cpp2
3 files changed, 29 insertions, 6 deletions
diff --git a/buildscripts/resmokeconfig/suites/sharded_core_txns.yml b/buildscripts/resmokeconfig/suites/sharded_core_txns.yml
index 653dc3fa7c3..556d7d2310e 100644
--- a/buildscripts/resmokeconfig/suites/sharded_core_txns.yml
+++ b/buildscripts/resmokeconfig/suites/sharded_core_txns.yml
@@ -21,9 +21,9 @@ selector:
- jstests/core/txns/disallow_operations_on_prepared_transaction.js
- jstests/core/txns/empty_prepare.js
- jstests/core/txns/ensure_active_txn_for_prepare_transaction.js
+ - jstests/core/txns/errors_on_committed_transaction.js
- jstests/core/txns/no_new_transactions_when_prepared_transaction_in_progress.js
- jstests/core/txns/no_writes_to_config_transactions_with_prepared_transaction.js
- - jstests/core/txns/prepare_committed_transaction.js
- jstests/core/txns/prepare_conflict.js
- jstests/core/txns/prepare_nonexistent_transaction.js
- jstests/core/txns/prepare_prepared_transaction.js
diff --git a/jstests/core/txns/prepare_committed_transaction.js b/jstests/core/txns/errors_on_committed_transaction.js
index 57b3c719075..dec27851ee9 100644
--- a/jstests/core/txns/prepare_committed_transaction.js
+++ b/jstests/core/txns/errors_on_committed_transaction.js
@@ -20,14 +20,18 @@
const doc = {x: 1};
- jsTestLog("Test that calling prepare on a committed transaction fails.");
session.startTransaction();
assert.commandWorked(sessionColl.insert(doc));
session.commitTransaction();
+
+ const txnNumber = NumberLong(session.getTxnNumber_forTesting());
+
+ // Call prepare on committed transaction.
+ jsTestLog("Test that calling prepare on a committed transaction fails.");
assert.commandFailedWithCode(sessionDB.adminCommand({
prepareTransaction: 1,
coordinatorId: "dummy",
- txnNumber: NumberLong(0),
+ txnNumber: txnNumber,
autocommit: false
}),
ErrorCodes.TransactionCommitted);
@@ -42,7 +46,7 @@
"providing autocommit to prepareTransaction.");
assert.commandFailedWithCode(
sessionDB.adminCommand(
- {prepareTransaction: 1, coordinatorId: "dummy", txnNumber: NumberLong(0)}),
+ {prepareTransaction: 1, coordinatorId: "dummy", txnNumber: txnNumber}),
ErrorCodes.InvalidOptions);
jsTestLog("Test the error precedence when calling prepare on a committed transaction and " +
@@ -50,11 +54,30 @@
assert.commandFailedWithCode(sessionDB.adminCommand({
prepareTransaction: 1,
coordinatorId: "dummy",
- txnNumber: NumberLong(0),
+ txnNumber: txnNumber,
autocommit: false,
startTransaction: true
}),
ErrorCodes.ConflictingOperationInProgress);
+ // Call commit on committed transaction without shell helper.
+ jsTestLog("Test that calling commit with invalid fields on a committed transaction fails.");
+ assert.commandFailedWithCode(
+ sessionDB.adminCommand(
+ {commitTransaction: 1, invalidField: 1, txnNumber: txnNumber, autocommit: false}),
+ 40415 /* IDL unknown field error */);
+
+ // Call abort on committed transaction without shell helper.
+ jsTestLog("Test that calling abort on a committed transaction fails.");
+ assert.commandFailedWithCode(
+ sessionDB.adminCommand({abortTransaction: 1, txnNumber: txnNumber, autocommit: false}),
+ ErrorCodes.TransactionCommitted);
+
+ jsTestLog("Test that calling abort with invalid fields on a committed transaction fails.");
+ assert.commandFailedWithCode(
+ sessionDB.adminCommand(
+ {abortTransaction: 1, invalidField: 1, txnNumber: txnNumber, autocommit: false}),
+ ErrorCodes.TransactionCommitted);
+
session.endSession();
}());
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp
index 2d2bb82cec1..512c0ce7070 100644
--- a/src/mongo/db/transaction_participant.cpp
+++ b/src/mongo/db/transaction_participant.cpp
@@ -1081,7 +1081,7 @@ void TransactionParticipant::abortActiveTransaction(OperationContext* opCtx) {
void TransactionParticipant::abortActiveUnpreparedOrStashPreparedTransaction(
OperationContext* opCtx) try {
stdx::unique_lock<stdx::mutex> lock(_mutex);
- if (_txnState.isInSet(lock, TransactionState::kNone)) {
+ if (_txnState.isInSet(lock, TransactionState::kNone | TransactionState::kCommitted)) {
// If there is no active transaction, do nothing.
return;
}