summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXueruiFa <xuerui.fa@mongodb.com>2021-02-05 15:56:28 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-02-06 01:53:22 +0000
commit395a73ccd6d053c964de7f0fe4f16920cb40350a (patch)
tree2764fc6c58c3f263d8ed572e3fda85316634d108
parentbd538c0b67fdb21c2be9ed4d124480f3d6fe9fa3 (diff)
downloadmongo-395a73ccd6d053c964de7f0fe4f16920cb40350a.tar.gz
SERVER-54339: Prevent spontaneous elections in rollback_crud_op_sequences.js
-rw-r--r--jstests/replsets/rollback_crud_op_sequences.js167
1 files changed, 52 insertions, 115 deletions
diff --git a/jstests/replsets/rollback_crud_op_sequences.js b/jstests/replsets/rollback_crud_op_sequences.js
index 74a10594bb7..54c580b6bd1 100644
--- a/jstests/replsets/rollback_crud_op_sequences.js
+++ b/jstests/replsets/rollback_crud_op_sequences.js
@@ -1,22 +1,14 @@
/*
* Basic test of a succesful replica set rollback for CRUD operations.
- *
- * This tests sets up a 3 node set, data-bearing nodes A and B and an arbiter.
- *
- * 1. A is elected PRIMARY and receives several writes, which are propagated to B.
- * 2. A is isolated from the rest of the set and B is elected PRIMARY.
- * 3. B receives several operations, which will later be undone during rollback.
- * 4. B is then isolated and A regains its connection to the arbiter.
- * 5. A receives many new operations, which B will replicate after rollback.
- * 6. B rejoins the set and goes through the rollback process.
- * 7. The contents of A and B are compare to ensure the rollback results in consistent nodes.
*/
+load('jstests/replsets/libs/rollback_test.js');
load("jstests/replsets/rslib.js");
(function() {
"use strict";
-// helper function for verifying contents at the end of the test
-var checkFinalResults = function(db) {
+
+// Helper function for verifying contents at the end of the test.
+const checkFinalResults = function(db) {
assert.eq(0, db.bar.count({q: 70}));
assert.eq(2, db.bar.count({q: 40}));
assert.eq(3, db.bar.count({a: "foo"}));
@@ -27,117 +19,62 @@ var checkFinalResults = function(db) {
assert.eq(0, db.kap2.find().itcount());
};
-var name = "rollback_crud_op_sequences";
-var replTest = new ReplSetTest({name: name, nodes: 3, useBridge: true});
-var nodes = replTest.nodeList();
-
-var conns = replTest.startSet();
-replTest.initiate({
- "_id": name,
- "members": [
- {"_id": 0, "host": nodes[0], priority: 3},
- {"_id": 1, "host": nodes[1]},
- {"_id": 2, "host": nodes[2], arbiterOnly: true}
- ]
-});
-
-// Make sure we have a primary and that that primary is node A
-replTest.waitForState(replTest.nodes[0], ReplSetTest.State.PRIMARY);
-var primary = replTest.getPrimary();
-var a_conn = conns[0];
-a_conn.setSecondaryOk();
-var A = a_conn.getDB("admin");
-var b_conn = conns[1];
-b_conn.setSecondaryOk();
-var B = b_conn.getDB("admin");
-assert.eq(primary, conns[0], "conns[0] assumed to be primary");
-assert.eq(a_conn, primary);
-
-// Wait for initial replication
-var a = a_conn.getDB("foo");
-var b = b_conn.getDB("foo");
+const rollbackTest = new RollbackTest();
-// initial data for both nodes
-assert.commandWorked(a.bar.insert({q: 0}));
-assert.commandWorked(a.bar.insert({q: 1, a: "foo"}));
-assert.commandWorked(a.bar.insert({q: 2, a: "foo", x: 1}));
-assert.commandWorked(a.bar.insert({q: 3, bb: 9, a: "foo"}));
-assert.commandWorked(a.bar.insert({q: 40, a: 1}));
-assert.commandWorked(a.bar.insert({q: 40, a: 2}));
-assert.commandWorked(a.bar.insert({q: 70, txt: 'willremove'}));
-a.createCollection("kap", {capped: true, size: 5000});
-assert.commandWorked(a.kap.insert({foo: 1}));
-// going back to empty on capped is a special case and must be tested
-a.createCollection("kap2", {capped: true, size: 5501});
-replTest.awaitReplication();
+const rollbackNode = rollbackTest.getPrimary();
+rollbackNode.setSecondaryOk();
+const syncSource = rollbackTest.getSecondary();
+syncSource.setSecondaryOk();
-// isolate A and wait for B to become primary
-conns[0].disconnect(conns[1]);
-conns[0].disconnect(conns[2]);
-assert.soon(function() {
- try {
- return B.hello().isWritablePrimary;
- } catch (e) {
- return false;
- }
-}, "node B did not become primary as expected", ReplSetTest.kDefaultTimeoutMS);
+const rollbackNodeDB = rollbackNode.getDB("foo");
+const syncSourceDB = syncSource.getDB("foo");
-// do operations on B and B alone, these will be rolled back
-assert.commandWorked(b.bar.insert({q: 4}));
-assert.commandWorked(b.bar.update({q: 3}, {q: 3, rb: true}));
-assert.commandWorked(b.bar.remove({q: 40})); // multi remove test
-assert.commandWorked(b.bar.update({q: 2}, {q: 39, rb: true}));
-// rolling back a delete will involve reinserting the item(s)
-assert.commandWorked(b.bar.remove({q: 1}));
-assert.commandWorked(b.bar.update({q: 0}, {$inc: {y: 1}}));
-assert.commandWorked(b.kap.insert({foo: 2}));
-assert.commandWorked(b.kap2.insert({foo: 2}));
-// create a collection (need to roll back the whole thing)
-assert.commandWorked(b.newcoll.insert({a: true}));
-// create a new empty collection (need to roll back the whole thing)
-b.createCollection("abc");
+// Insert initial data for both nodes.
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 0}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 1, a: "foo"}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 2, a: "foo", x: 1}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 3, bb: 9, a: "foo"}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 40, a: 1}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 40, a: 2}));
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 70, txt: 'willremove'}));
+rollbackNodeDB.createCollection("kap", {capped: true, size: 5000});
+assert.commandWorked(rollbackNodeDB.kap.insert({foo: 1}));
+// Going back to empty on capped is a special case and must be tested.
+rollbackNodeDB.createCollection("kap2", {capped: true, size: 5501});
+rollbackTest.awaitReplication();
-// isolate B, bring A back into contact with the arbiter, then wait for A to become primary
-// insert new data into A so that B will need to rollback when it reconnects to A
-conns[1].disconnect(conns[2]);
-assert.soon(function() {
- try {
- return !B.hello().isWritablePrimary;
- } catch (e) {
- return false;
- }
-});
+rollbackTest.transitionToRollbackOperations();
-conns[0].reconnect(conns[2]);
-assert.soon(function() {
- try {
- return A.hello().isWritablePrimary;
- } catch (e) {
- return false;
- }
-});
-assert.gte(a.bar.find().itcount(), 1, "count check");
-assert.commandWorked(a.bar.insert({txt: 'foo'}));
-assert.commandWorked(a.bar.remove({q: 70}));
-assert.commandWorked(a.bar.update({q: 0}, {$inc: {y: 33}}));
+// These operations are only done on 'rollbackNode' and should eventually be rolled back.
+assert.commandWorked(rollbackNodeDB.bar.insert({q: 4}));
+assert.commandWorked(rollbackNodeDB.bar.update({q: 3}, {q: 3, rb: true}));
+assert.commandWorked(rollbackNodeDB.bar.remove({q: 40})); // multi remove test
+assert.commandWorked(rollbackNodeDB.bar.update({q: 2}, {q: 39, rb: true}));
+// Rolling back a delete will involve reinserting the item(s).
+assert.commandWorked(rollbackNodeDB.bar.remove({q: 1}));
+assert.commandWorked(rollbackNodeDB.bar.update({q: 0}, {$inc: {y: 1}}));
+assert.commandWorked(rollbackNodeDB.kap.insert({foo: 2}));
+assert.commandWorked(rollbackNodeDB.kap2.insert({foo: 2}));
+// Create a collection (need to roll back the whole thing).
+assert.commandWorked(rollbackNodeDB.newcoll.insert({a: true}));
+// Create a new empty collection (need to roll back the whole thing).
+rollbackNodeDB.createCollection("abc");
-// A is 1 2 3 7 8
-// B is 1 2 3 4 5 6
-// put B back in contact with A and arbiter, as A is primary, B will rollback and then catch up
-conns[1].reconnect(conns[2]);
-conns[0].reconnect(conns[1]);
+rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
-awaitOpTime(b_conn, a_conn);
+// Insert new data into syncSource so that rollbackNode enters rollback when it is reconnected.
+// These operations should not be rolled back.
+assert.gte(syncSourceDB.bar.find().itcount(), 1, "count check");
+assert.commandWorked(syncSourceDB.bar.insert({txt: 'foo'}));
+assert.commandWorked(syncSourceDB.bar.remove({q: 70}));
+assert.commandWorked(syncSourceDB.bar.update({q: 0}, {$inc: {y: 33}}));
-// await steady state and ensure the two nodes have the same contents
-replTest.awaitSecondaryNodes();
-replTest.awaitReplication();
-checkFinalResults(a);
-checkFinalResults(b);
+rollbackTest.transitionToSyncSourceOperationsDuringRollback();
+rollbackTest.transitionToSteadyStateOperations();
-// Verify data consistency between nodes.
-replTest.checkReplicatedDataHashes();
-replTest.checkOplogs();
+rollbackTest.awaitReplication();
+checkFinalResults(rollbackNodeDB);
+checkFinalResults(syncSourceDB);
-replTest.stopSet(15);
+rollbackTest.stop();
}());