/*
* This test demonstrates 2 primaries existing in the same replica set and both primaries
* can satisfy majority write concern.
*
* Basically the test simulates below scenario
* Note: 'P' refers primary, 'S' refers to secondary.
* 1) [P, S0, S1] // Start a 3 node replica set.
* 2) Partition A: [P] Partition B: [S0->P, S1] // Create n/w partition A & B.
* 3) Partition A: [P, S2] Partition B: [P, S1] // Replace S1 by a new node S2 to Partition A using the member id of S1.
*/
load('jstests/replsets/rslib.js');
(function() {
'use strict';
// Start a 3 node replica set.
// [P, S0, S1]
const rst = new ReplSetTest({
nodes: [{}, {}, {rsConfig: {priority: 0}}],
useBridge: true
});
// Disable Chaining and disable automatic election from happening due to liveness timeout.
var config = rst.getReplSetConfig();
config.settings = config.settings || {};
config.settings["chainingAllowed"] = false;
config.settings["electionTimeoutMillis"] = ReplSetTest.kForeverMillis;
rst.startSet();
rst.initiate(config);
const dbName = jsTest.name();
const collName = "coll";
let primary1 = rst.getPrimary();
const primaryDB = primary1.getDB(dbName);
const primaryColl = primaryDB[collName];
const secondaries = rst.getSecondaries();
jsTestLog("Do a document write");
assert.commandWorked(primaryColl.insert({_id: 1, x: 1}, {"writeConcern": {"w": 3}}));
rst.awaitReplication();
// Create a n/w partition such that we result in this state [P] [S0, S1].
jsTestLog("Disconnect primary1 from all secondaries");
primary1.disconnect([secondaries[0], secondaries[1]]);
jsTestLog("Make secondary0 to be become primary");
assert.commandWorked(secondaries[0].adminCommand({"replSetStepUp": 1}));
// Now our network topology will be [P] [S0->P, S1].
jsTestLog("Wait for secondary0 to become master");
checkLog.contains(secondaries[0], "Transition to primary complete");
let primary2 = secondaries[0];
// Make sure the new writes is able to propagate to the newly added node.
jsTestLog("Do a document write on the primary2");
assert.commandWorked(
primary2.getDB(dbName)[collName].insert({_id: 2, x: 2}, {"writeConcern": {"w": "majority"}}));
jsTestLog("Adding a new voting node to the replica set");
let origConfig = rst.getReplSetConfigFromNode(primary1.nodeId);
const node4 = rst.add({
rsConfig: {priority: 0, votes: 1},
setParameter: {
'numInitialSyncAttempts': 1
}
});
// Simulate this network topology [P, S2] [P, S1].
node4.disconnect([secondaries[0], secondaries[1]]);
// Run a reconfig command on the primary1 to add node 4
var newConfig = rst.getReplSetConfig();
// Only reset members.
origConfig.members[2].host = newConfig.members[3].host;
origConfig.version += 1;
assert.adminCommandWorkedAllowingNetworkError(
primary1, {replSetReconfig: origConfig, maxTimeMS: ReplSetTest.kDefaultTimeoutMS});
jsTestLog(
"Do some document writes to verify we have 2 primaries and both satisfy write concern majority");
assert.commandWorked(primary1.getDB(dbName)[collName].insert({_id: 3, x: "primary1 Doc"},
{"writeConcern": {"w": "majority"}}));
assert.commandWorked(primary2.getDB(dbName)[collName].insert({_id: 6, x: "primary2 Doc"},
{"writeConcern": {"w": "majority"}}));
jsTestLog("Verify our primary1 can be get re-elected.");
assert.commandWorked(primary1.adminCommand({"replSetStepDown": 1000, "force": true}));
assert.commandWorked(primary1.adminCommand({replSetFreeze: 0}));
assert.commandWorked(primary1.adminCommand({"replSetStepUp": 1}));
jsTestLog("Test completed");
rst.stopSet();
}());