/*
|
* 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();
|
}());
|