summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis Osta <luis.osta@mongodb.com>2020-07-15 15:10:09 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-15 15:22:35 +0000
commite4ad46c0fab6ce2b633f212db65ab5479c4c191e (patch)
treea767dfbe20a6fdd02df4315683d907a93d60d45f
parent29f80326b16136e36d4f9eb1054d801409abff18 (diff)
downloadmongo-e4ad46c0fab6ce2b633f212db65ab5479c4c191e.tar.gz
SERVER-49044 Make AsyncRequestSender not retry remote command requests with startTransaction=true
-rw-r--r--jstests/sharding/mongos_not_retry_commands_in_transactions.js74
-rw-r--r--src/mongo/s/async_requests_sender.cpp5
2 files changed, 76 insertions, 3 deletions
diff --git a/jstests/sharding/mongos_not_retry_commands_in_transactions.js b/jstests/sharding/mongos_not_retry_commands_in_transactions.js
new file mode 100644
index 00000000000..7fd6d8d5ad7
--- /dev/null
+++ b/jstests/sharding/mongos_not_retry_commands_in_transactions.js
@@ -0,0 +1,74 @@
+/*
+ * Tests that mongos doesn't retry commands with startTransaction=true.
+ * @tags: [requires_fcv_46]
+ */
+(function() {
+'use strict';
+
+const setCommandToFail = (nodeConnection, command, namespace) => {
+ return nodeConnection.adminCommand({
+ configureFailPoint: 'failCommand',
+ mode: {times: 1},
+ data: {
+ errorCode: ErrorCodes.InterruptedDueToReplStateChange,
+ failCommands: [command],
+ namespace,
+ failInternalCommands: true
+ }
+ });
+};
+
+const kDbName = "testDb";
+const kCollName = "testColl";
+const kNs = `${kDbName}.${kCollName}`;
+
+const kDoc0 = {
+ _id: 0
+};
+const kDoc1 = {
+ _id: 1
+};
+
+let transactionNumber = 1;
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ rs: {nodes: 1},
+});
+
+// Initializes test and inserts dummy document
+jsTest.log("Inserting test document.");
+const mongosDB = st.s0.startSession().getDatabase(kDbName);
+const primaryConnection = st.rs0.getPrimary();
+
+assert.commandWorked(mongosDB.runCommand({
+ insert: kCollName,
+ documents: [kDoc0],
+}));
+
+// Set the failCommand failpoint to make the next 'find' command fail once due to a failover.
+// Start a transaction & execute a find command.
+// It should fail once due to the 'failCommand' failpoint and should not be retried.
+jsTest.log(
+ "Testing that mongos doesn't retry the read command with startTransaction=true on replication set failover.");
+assert.commandWorked(setCommandToFail(primaryConnection, "find", kNs));
+
+assert.commandFailedWithCode(mongosDB.runCommand({
+ find: kCollName,
+ filter: kDoc0,
+ startTransaction: true,
+ txnNumber: NumberLong(transactionNumber++),
+ stmtId: NumberInt(0),
+ autocommit: false
+}),
+ ErrorCodes.InterruptedDueToReplStateChange);
+
+jsTest.log("Testing that mongos retries retryable writes on failover.");
+assert.commandWorked(setCommandToFail(primaryConnection, "insert", kNs));
+
+assert.commandWorked(mongosDB.runCommand(
+ {insert: kCollName, documents: [kDoc1], txnNumber: NumberLong(transactionNumber++)}));
+
+st.stop();
+})(); \ No newline at end of file
diff --git a/src/mongo/s/async_requests_sender.cpp b/src/mongo/s/async_requests_sender.cpp
index 36f91459d29..7cca30f0b99 100644
--- a/src/mongo/s/async_requests_sender.cpp
+++ b/src/mongo/s/async_requests_sender.cpp
@@ -272,9 +272,9 @@ auto AsyncRequestsSender::RemoteData::handleResponse(RemoteCommandOnAnyCallbackA
}
shard->updateReplSetMonitor(failedTargets.front(), status);
-
+ bool isStartingTransaction = _cmdObj.getField("startTransaction").booleanSafe();
if (!_ars->_stopRetrying && shard->isRetriableError(status.code(), _ars->_retryPolicy) &&
- _retryCount < kMaxNumFailedHostRetryAttempts) {
+ _retryCount < kMaxNumFailedHostRetryAttempts && !isStartingTransaction) {
LOGV2_DEBUG(4615637,
1,
@@ -284,7 +284,6 @@ auto AsyncRequestsSender::RemoteData::handleResponse(RemoteCommandOnAnyCallbackA
"shardId"_attr = _shardId,
"hosts"_attr = failedTargets,
"error"_attr = redact(status));
-
++_retryCount;
_shardHostAndPort.reset();
// retry through recursion