summaryrefslogtreecommitdiff
path: root/jstests/sharding/txn_single_write_shard_failover.js
diff options
context:
space:
mode:
authorEsha Maharishi <esha.maharishi@mongodb.com>2020-05-19 11:25:17 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-05-20 22:25:47 +0000
commitbe253e1614bb05dc9a9ace507b263fb4885dcdee (patch)
tree03a16f6b2aa3a6bd77ec11deace33a8face7c1c4 /jstests/sharding/txn_single_write_shard_failover.js
parentfbf56a4aee8ccb7bff8d3e8c3c32c7849869bb54 (diff)
downloadmongo-be253e1614bb05dc9a9ace507b263fb4885dcdee.tar.gz
SERVER-48307 Disable single-write-shard transaction commit optimization
Diffstat (limited to 'jstests/sharding/txn_single_write_shard_failover.js')
-rw-r--r--jstests/sharding/txn_single_write_shard_failover.js72
1 files changed, 72 insertions, 0 deletions
diff --git a/jstests/sharding/txn_single_write_shard_failover.js b/jstests/sharding/txn_single_write_shard_failover.js
new file mode 100644
index 00000000000..f21ba4d5f81
--- /dev/null
+++ b/jstests/sharding/txn_single_write_shard_failover.js
@@ -0,0 +1,72 @@
+/**
+ * Runs a single-write-shard transaction which commits, but for which the client retries commit and
+ * a read-only shard fails over before the second commit attempt.
+ *
+ * The second commit attempt should still return a commit decision.
+ *
+ * This test was written to reproduce the bug in the original single-write-shard transaction commit
+ * optimization where if a read-only shard failed over before the client sent a second commit
+ * attempt, the second commit attempt would return NoSuchTransaction with TransientTransactionError,
+ * causing the client to retry the whole transaction at a higher transaction number and the
+ * transaction's write to be applied twice.
+ *
+ * TODO (SERVER-48341): Remove requires_fcv_46 after backporting SERVER-48307 to 4.4.
+ * requires_find_command because legacy queries cannot be run in a session.
+ * @tags: [requires_find_command, requires_fcv_46, uses_transactions, uses_multi_shard_transaction]
+ */
+
+(function() {
+'use strict';
+
+load("jstests/libs/fail_point_util.js");
+
+const db1Name = "db1";
+const coll1Name = "foo";
+const ns1 = db1Name + "." + coll1Name;
+
+const db2Name = "db2";
+const coll2Name = "bar";
+const ns2 = db2Name + "." + coll2Name;
+
+const st = new ShardingTest({
+ shards: {rs0: {nodes: 2}, rs1: {nodes: 1}},
+ config: 1,
+ other: {
+ mongosOptions: {verbose: 3},
+ }
+});
+
+jsTest.log("Create two databases on different primary shards.");
+// enableSharding creates the databases.
+assert.commandWorked(st.s.adminCommand({enableSharding: db1Name}));
+assert.commandWorked(st.s.adminCommand({enableSharding: db2Name}));
+assert.commandWorked(st.s.adminCommand({movePrimary: db1Name, to: st.shard0.shardName}));
+assert.commandWorked(st.s.adminCommand({movePrimary: db2Name, to: st.shard1.shardName}));
+
+jsTest.log("Insert data on both shards.");
+// This ensures all nodes refresh their routing caches.
+st.s.getDB(db1Name).getCollection(coll1Name).insert({_id: "dummy"});
+st.s.getDB(db2Name).getCollection(coll2Name).insert({_id: "dummy"});
+
+jsTest.log("Run a single-write-shard transaction and commit it.");
+const session = st.s.startSession();
+session.startTransaction();
+session.getDatabase(db1Name).getCollection(coll1Name).findOne({_id: "readOperationOnShard0"});
+session.getDatabase(db2Name).getCollection(coll2Name).insert({_id: "writeOperationOnShard1"});
+// Use adminCommand so we can pass writeConcern.
+assert.commandWorked(st.s.adminCommand({
+ commitTransaction: 1,
+ lsid: session.getSessionId(),
+ txnNumber: session.getTxnNumber_forTesting(),
+ autocommit: false,
+ writeConcern: {w: "majority"},
+}));
+
+jsTest.log("Induce a failover on the read shard.");
+assert.commandWorked(st.rs0.getPrimary().adminCommand({replSetStepDown: 60, force: true}));
+
+jsTest.log("Make second attempt to commit, should still return that the transaction committed");
+assert.commandWorked(session.commitTransaction_forTesting());
+
+st.stop();
+})();