summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorVesselina Ratcheva <vesselina.ratcheva@10gen.com>2019-06-06 16:44:48 -0400
committerVesselina Ratcheva <vesselina.ratcheva@10gen.com>2019-06-12 14:17:26 -0400
commit259bd089d0265ac510acbe4512eb706cd553562b (patch)
tree579f5e948821ae242325ad5ece6cd166d7f1244a /jstests
parentdfa8658c18142c560447c7bf6f34a6f788593d28 (diff)
downloadmongo-259bd089d0265ac510acbe4512eb706cd553562b.tar.gz
SERVER-41207 Test committing prepared transactions after stepdown due to reconfig
Diffstat (limited to 'jstests')
-rw-r--r--jstests/replsets/libs/prepare_failover_due_to_reconfig.js72
-rw-r--r--jstests/replsets/prepare_survives_primary_reconfig_failover.js14
-rw-r--r--jstests/replsets/prepare_survives_reconfig_via_heartbeat_failover.js15
3 files changed, 101 insertions, 0 deletions
diff --git a/jstests/replsets/libs/prepare_failover_due_to_reconfig.js b/jstests/replsets/libs/prepare_failover_due_to_reconfig.js
new file mode 100644
index 00000000000..cf5b4e58fd8
--- /dev/null
+++ b/jstests/replsets/libs/prepare_failover_due_to_reconfig.js
@@ -0,0 +1,72 @@
+"use strict";
+
+/**
+ * Library used to test that prepared transactions survive failovers due to reconfig.
+ */
+
+var testPrepareFailoverDueToReconfig = function(name, reconfigOnPrimary) {
+ load("jstests/core/txns/libs/prepare_helpers.js");
+
+ const dbName = "test";
+ const collName = name;
+
+ const rst = new ReplSetTest({name: name, nodes: 2});
+ const nodes = rst.nodeList();
+
+ rst.startSet();
+ rst.initiate({
+ "_id": name,
+ "members": [
+ {/* primary */ "_id": 0, "host": nodes[0]},
+ {/* secondary */ "_id": 1, "host": nodes[1], "priority": 0}
+ ]
+ });
+
+ const primary = rst.getPrimary();
+ const secondary = rst.getSecondary();
+
+ const testDB = primary.getDB(dbName);
+ const testColl = testDB.getCollection(collName);
+
+ const oldDoc = {_id: 42, "is": "old"};
+ const newDoc = {_id: 42, "is": "new"};
+
+ // First create the collection.
+ assert.commandWorked(testColl.insert(oldDoc));
+
+ const session = primary.startSession();
+ const sessionDB = session.getDatabase(dbName);
+ const sessionColl = sessionDB.getCollection(collName);
+
+ session.startTransaction();
+ assert.commandWorked(sessionColl.update(oldDoc, newDoc));
+
+ // Prepare a transaction. This will be replicated to the secondary.
+ const prepareTimestamp = PrepareHelpers.prepareTransaction(session);
+
+ // Now reconfig to force a failover.
+ let config = rst.getReplSetConfigFromNode();
+
+ config.members[0].priority = 0;
+ config.members[1].priority = 1;
+ config.version++;
+
+ // Run the reconfig command on whichever node the caller targeted.
+ const reconfigTarget = reconfigOnPrimary ? primary : secondary;
+ assert.commandWorked(reconfigTarget.adminCommand({replSetReconfig: config, force: true}));
+ rst.waitForState(primary, ReplSetTest.State.SECONDARY);
+
+ // Wait for the old secondary to become the new primary.
+ const newPrimary = rst.getPrimary();
+ assert.neq(primary, newPrimary, "failover did not occur");
+
+ // Commit the prepared transaction on the new primary.
+ const newSession = new _DelegatingDriverSession(newPrimary, session);
+ assert.commandWorked(PrepareHelpers.commitTransaction(newSession, prepareTimestamp));
+
+ // Verify the effect of the transaction.
+ const doc = newPrimary.getDB(dbName).getCollection(collName).findOne({});
+ assert.docEq(newDoc, doc);
+
+ rst.stopSet();
+}; \ No newline at end of file
diff --git a/jstests/replsets/prepare_survives_primary_reconfig_failover.js b/jstests/replsets/prepare_survives_primary_reconfig_failover.js
new file mode 100644
index 00000000000..8db3322b796
--- /dev/null
+++ b/jstests/replsets/prepare_survives_primary_reconfig_failover.js
@@ -0,0 +1,14 @@
+/**
+ * Tests that prepared transactions can safely be committed after a failover due to reconfig. We
+ * issue the reconfig command directly against the primary in this test.
+ *
+ * @tags: [uses_transactions, uses_prepare_transaction]
+ */
+(function() {
+ "use strict";
+ load("jstests/replsets/libs/prepare_failover_due_to_reconfig.js");
+
+ let testName = "prepare_survives_primary_reconfig_failover";
+
+ testPrepareFailoverDueToReconfig(testName, /* reconfigOnPrimary */ true);
+})();
diff --git a/jstests/replsets/prepare_survives_reconfig_via_heartbeat_failover.js b/jstests/replsets/prepare_survives_reconfig_via_heartbeat_failover.js
new file mode 100644
index 00000000000..bf4a0c565a9
--- /dev/null
+++ b/jstests/replsets/prepare_survives_reconfig_via_heartbeat_failover.js
@@ -0,0 +1,15 @@
+/**
+ * Tests that prepared transactions can safely be committed after a failover due to reconfig. We
+ * issue the reconfig command against the secondary in this test, so that the primary can learn of
+ * the new config via a heartbeat from that secondary.
+ *
+ * @tags: [uses_transactions, uses_prepare_transaction]
+ */
+(function() {
+ "use strict";
+ load("jstests/replsets/libs/prepare_failover_due_to_reconfig.js");
+
+ let testName = "prepare_survives_reconfig_via_heartbeat_failover";
+
+ testPrepareFailoverDueToReconfig(testName, /* reconfigOnPrimary */ false);
+})();