diff options
author | Ali Mir <ali.mir@mongodb.com> | 2020-02-24 18:01:15 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-10 23:49:38 +0000 |
commit | 6ba8fb61e5f323d0211b39c74aded5df86bbba83 (patch) | |
tree | 50979bd7e622b70bb05d0297d577efdc30afa99e /jstests | |
parent | d3c55652b6cab504ad7acf32b16298809ac9f5e6 (diff) | |
download | mongo-6ba8fb61e5f323d0211b39c74aded5df86bbba83.tar.gz |
SERVER-45088 Simplify safe reconfig avoids diverging configs test
(cherry picked from commit 98299f2f7eb295361cee2aea4dc03b952483d715)
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/replsets/reconfig_avoids_diverging_configs.js | 123 |
1 files changed, 48 insertions, 75 deletions
diff --git a/jstests/replsets/reconfig_avoids_diverging_configs.js b/jstests/replsets/reconfig_avoids_diverging_configs.js index 6dbd0507b2f..6697b0497a5 100644 --- a/jstests/replsets/reconfig_avoids_diverging_configs.js +++ b/jstests/replsets/reconfig_avoids_diverging_configs.js @@ -5,16 +5,13 @@ * C2: {n1,n3,n4} * The C1 quorum {n1,n2} and the C2 quorum {n3,n4} do not overlap. * - * 1. Node1 is the initial primary. - * 2. Disconnect node4 from all three other nodes. - * 3. Step down node1 and step up node2. - * 4. Disconnect the current primary, node2, from all other nodes. - * 5. Issue a reconfig to node2 that removes node4. - * 6. Reconnect node4 to the current secondaries, node1 and node3. - * 7. Step up node3, which creates a two primary scenario. - * 8. Issue a reconfig to node3 that removes node2. We now have diverging configs + * 1. Node0 is the initial primary. + * 2. Disconnect node0 from all other nodes. + * 3. Issue a reconfig to node0 that removes node3. + * 4. Step up node1, which creates a two primary scenario. + * 5. Issue a reconfig to node1 that removes node2. We now have diverging configs * from two different primaries. - * 9. Reconnect node2 to the rest of the set and verify that its reconfig fails. + * 6. Reconnect node0 to the rest of the set and verify that its reconfig fails. * * @tags: [requires_fcv_44] */ @@ -25,98 +22,74 @@ load('jstests/libs/test_background_ops.js'); load("jstests/replsets/rslib.js"); load('jstests/aggregation/extras/utils.js'); -const dbName = "test"; -const collName = "coll"; let rst = new ReplSetTest({nodes: 4, useBridge: true}); rst.startSet(); rst.initiateWithHighElectionTimeout(); -const node1 = rst.getPrimary(); -const secondaries = rst.getSecondaries(); -const node2 = secondaries[0]; -const node3 = secondaries[1]; -const node4 = secondaries[2]; -const coll = node1.getDB(dbName)[collName]; +const node0 = rst.getPrimary(); +const [node1, node2, node3] = rst.getSecondaries(); +jsTestLog("Current replica set topology: [node0 (Primary), node1, node2, node3]"); -// Partition the 4th node. -node4.disconnect([node1, node2, node3]); - -jsTestLog("Current replica set topology: [Primary-Secondary-Secondary] [Secondary]"); -assert.commandWorked(node1.adminCommand({replSetStepDown: 120})); -// Step up a new primary in the partitioned repl set. -assert.commandWorked(node2.adminCommand({replSetStepUp: 1})); - -// Wait until the config has been committed. -assert.soon(() => isConfigCommitted(rst.getPrimary())); // The quorum check places stricter bounds on the safe reconfig // protocol and won't allow this specific scenario of diverging configs // to happen. However, it's still worth testing the original reconfig // protocol that omitted the check for correctness. configureFailPoint(rst.getPrimary(), "omitConfigQuorumCheck"); -// Reconfig to remove the 4th node. +// Reconfig to remove the node3. The new config, C1, is now {node0, node1, node2}. const C1 = Object.assign({}, rst.getReplSetConfigFromNode()); C1.members = C1.members.slice(0, 3); // Remove the last node. -C1.version++; +// Increase the C1 version by a high number to ensure the following config +// C2 will win the propagation by having a higher term. +C1.version = C1.version + 1000; +waitForConfigReplication(node0); +rst.awaitReplication(); jsTestLog("Disconnecting the primary from other nodes"); -assert.eq(rst.getPrimary(), node2); -node2.disconnect([node1, node3, node4]); -jsTestLog("Current replica set topology: [Primary] [Secondary-Secondary] [Secondary]"); +assert.eq(rst.getPrimary(), node0); +node0.disconnect([node1, node2, node3]); +jsTestLog("Current replica set topology: [node0 (Primary)] [node1, node2, node3]"); // Create parallel shell to execute reconfig on partitioned primary. -// This reconfig will succeed due to the omission of the quorum check, but -// will not get propagated. -startParallelShell(funWithArgs(function(config) { - assert.commandWorked(db.getMongo().adminCommand({replSetReconfig: config})); - }, C1), node2.port); +// This reconfig will not get propagated. +const parallelShell = startParallelShell( + funWithArgs(function(config) { + assert.commandFailedWithCode(db.getMongo().adminCommand({replSetReconfig: config}), + ErrorCodes.InterruptedDueToReplStateChange, + "Reconfig C1 should fail"); + }, C1), node0.port); -// Reconnect the 4th node to the secondaries. -node4.reconnect([node1, node3]); -node3.adminCommand({replSetStepUp: 1}); -rst.awaitNodesAgreeOnPrimary(rst.kDefaultTimeoutMS, [node1, node3, node4]); -jsTestLog("Current replica set topology: [Primary-Secondary-Secondary] [Primary]"); -assert.soon(function() { - return isConfigCommitted(node3); -}); +assert.commandWorked(node1.adminCommand({replSetStepUp: 1})); +rst.awaitNodesAgreeOnPrimary(rst.kDefaultTimeoutMS, [node1, node2, node3], 1); +jsTestLog("Current replica set topology: [node0 (Primary)] [node1 (Primary), node2, node3]"); +assert.soon(() => node1.getDB('admin').runCommand({ismaster: 1}).ismaster); +assert.soon(() => isConfigCommitted(node1)); // Reconfig to remove a secondary. We need to specify the node to get the original -// config from as there are two primaries, node2 and node3, in the replset. -let C2 = Object.assign({}, rst.getReplSetConfigFromNode(2)); -const removedSecondary = C2.members.splice(0, 1); +// config from as there are two primaries, node0 and node1, in the replset. +// The new config is now {node0, node1, node3}. +let C2 = Object.assign({}, rst.getReplSetConfigFromNode(1)); +const removedSecondary = C2.members.splice(2, 1); C2.version++; -assert.commandWorked(node3.adminCommand({replSetReconfig: C2})); -assert.soon(() => isConfigCommitted(node3)); +assert.commandWorked(node1.adminCommand({replSetReconfig: C2})); +assert.soon(() => isConfigCommitted(node1)); -// Reconnect partitioned node to the other nodes. -node2.reconnect([node3, node4]); +// Reconnect the partitioned primary, node0, to the other nodes. +node0.reconnect([node1, node2, node3]); // The newly connected node will receive a heartbeat with a higher term, and -// step down from being primary. The reconfig command issued to this node will fail. -rst.waitForState(node2, ReplSetTest.State.SECONDARY); - -// Make sure the newly connected secondary has updated its config. -assert.soon(function() { - const node2TermUpdated = bsonWoCompare(node2.adminCommand({replSetGetStatus: 1}).term, - node3.adminCommand({replSetGetStatus: 1}).term) == 0; - const node2ConfigTermUpdated = - node2.adminCommand({replSetGetStatus: 1}).members[1].configTerm == - node3.adminCommand({replSetGetStatus: 1}).members[2].configTerm; - const node2ConfigVersionUpdated = - node2.adminCommand({replSetGetStatus: 1}).members[1].configVersion == - node3.adminCommand({replSetGetStatus: 1}).members[2].configVersion; - return node2TermUpdated && node2ConfigTermUpdated && node2ConfigVersionUpdated; -}); +// step down from being primary. The reconfig command issued to this node, C1, will fail. +rst.waitForState(node0, ReplSetTest.State.SECONDARY); +rst.awaitNodesAgreeOnPrimary(rst.kDefaultTimeoutMS, [node0, node1, node3]); +waitForConfigReplication(node1); +assert.eq(C2, rst.getReplSetConfigFromNode()); -// Reconnect the 4th node to return to a stable state. -let C3 = Object.assign({}, rst.getReplSetConfigFromNode(2)); +// The new config is now {node0, node1, node2, node3}. +let C3 = Object.assign({}, rst.getReplSetConfigFromNode(1)); C3.members.push(removedSecondary[0]); C3.version++; -node1.reconnect([node2, node3, node4]); -assert.commandWorked(node3.adminCommand({replSetReconfig: C3})); -assert.soon(function() { - return isConfigCommitted(node3); -}); +assert.commandWorked(node1.adminCommand({replSetReconfig: C3})); +assert.soon(() => isConfigCommitted(node1)); rst.awaitNodesAgreeOnPrimary(); -rst.awaitNodesAgreeOnConfigVersion(); +parallelShell(); rst.stopSet(); }()); |