2014-11-05 11:49:27 -05:00
|
|
|
// Ensure writes do not prevent a node from Stepping down
|
|
|
|
|
// 1. Start up a 3 node set (1 arbiter).
|
2015-10-09 19:40:08 -04:00
|
|
|
// 2. Stop replication on the SECONDARY using a fail point.
|
2014-11-05 11:49:27 -05:00
|
|
|
// 3. Do one write and then spin up a second shell which asks the PRIMARY to StepDown.
|
|
|
|
|
// 4. Once StepDown has begun, spin up a third shell which will attempt to do writes, which should
|
|
|
|
|
// block waiting for StepDown to release its lock.
|
2015-10-09 19:40:08 -04:00
|
|
|
// 5. Once a write is blocked, restart replication on the SECONDARY.
|
2014-11-05 11:49:27 -05:00
|
|
|
// 6. Wait for PRIMARY to StepDown.
|
|
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
|
"use strict";
|
|
|
|
|
var name = "stepDownWithLongWait";
|
|
|
|
|
var replSet = new ReplSetTest({name: name, nodes: 3});
|
|
|
|
|
var nodes = replSet.nodeList();
|
|
|
|
|
replSet.startSet();
|
|
|
|
|
replSet.initiate({"_id" : name,
|
|
|
|
|
"members" : [
|
|
|
|
|
{"_id" : 0, "host" : nodes[0], "priority" : 3},
|
|
|
|
|
{"_id" : 1, "host" : nodes[1]},
|
|
|
|
|
{"_id" : 2, "host" : nodes[2], "arbiterOnly" : true}]});
|
|
|
|
|
|
2015-12-10 10:21:51 -05:00
|
|
|
replSet.waitForState(replSet.nodes[0], ReplSetTest.State.PRIMARY, 60 * 1000);
|
2014-11-05 11:49:27 -05:00
|
|
|
var primary = replSet.getPrimary();
|
2015-10-09 19:40:08 -04:00
|
|
|
|
2015-01-27 10:29:02 -05:00
|
|
|
var secondary = replSet.getSecondary();
|
2015-10-09 19:40:08 -04:00
|
|
|
jsTestLog('Disable replication on the SECONDARY ' + secondary.host);
|
|
|
|
|
assert.commandWorked(
|
|
|
|
|
secondary.getDB('admin').runCommand(
|
|
|
|
|
{configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'}
|
|
|
|
|
),
|
|
|
|
|
'Failed to configure rsSyncApplyStop failpoint.'
|
|
|
|
|
);
|
2014-11-05 11:49:27 -05:00
|
|
|
|
|
|
|
|
jsTestLog("do a write then ask the PRIMARY to stepdown");
|
|
|
|
|
var options = {writeConcern: {w: 1, wtimeout: 60000}};
|
|
|
|
|
assert.writeOK(primary.getDB(name).foo.insert({x: 1}, options));
|
2015-10-05 14:35:01 -04:00
|
|
|
var stepDownSecs = 60;
|
|
|
|
|
var secondaryCatchUpPeriodSecs = 60;
|
|
|
|
|
var stepDownCmd = "db.getSiblingDB('admin').runCommand({" +
|
|
|
|
|
"replSetStepDown: " + stepDownSecs + ", " +
|
|
|
|
|
"secondaryCatchUpPeriodSecs: " + secondaryCatchUpPeriodSecs +
|
|
|
|
|
"});";
|
|
|
|
|
var stepDowner = startParallelShell(stepDownCmd, primary.port);
|
|
|
|
|
|
2014-11-05 11:49:27 -05:00
|
|
|
assert.soon(function() {
|
|
|
|
|
var res = primary.getDB('admin').currentOp(true);
|
|
|
|
|
for (var entry in res.inprog) {
|
|
|
|
|
if (res.inprog[entry]["query"] && res.inprog[entry]["query"]["replSetStepDown"] === 60){
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printjson(res);
|
|
|
|
|
return false;
|
2015-10-05 14:35:01 -04:00
|
|
|
}, "global shared lock not acquired", 30000, 1000);
|
2014-11-05 11:49:27 -05:00
|
|
|
|
|
|
|
|
jsTestLog("do a write and wait for it to be waiting for a lock");
|
|
|
|
|
var updateCmd = function() {
|
2015-10-09 19:40:08 -04:00
|
|
|
jsTestLog('Updating document on the primary. Blocks until the primary has stepped down.')
|
|
|
|
|
try {
|
2014-11-05 11:49:27 -05:00
|
|
|
var res = db.getSiblingDB("stepDownWithLongWait").foo.update({}, {$inc: {x: 1}});
|
2015-10-09 19:40:08 -04:00
|
|
|
jsTestLog('Unexpected successful update operation on the primary during step down: ' +
|
|
|
|
|
tojson(res));
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
// Not important what error we get back. The client will probably be disconnected by
|
|
|
|
|
// the primary with a "error doing query: failed" message.
|
|
|
|
|
jsTestLog('Update operation returned with result: ' + tojson(e));
|
2014-11-05 11:49:27 -05:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
var writer = startParallelShell(updateCmd, primary.port);
|
|
|
|
|
assert.soon(function() {
|
|
|
|
|
var res = primary.getDB(name).currentOp();
|
|
|
|
|
for (var entry in res.inprog) {
|
|
|
|
|
if (res.inprog[entry]["waitingForLock"]) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printjson(res);
|
|
|
|
|
return false;
|
2015-10-05 14:35:01 -04:00
|
|
|
}, "write failed to block on global lock", 30000, 1000);
|
2014-11-05 11:49:27 -05:00
|
|
|
|
2015-10-09 19:40:08 -04:00
|
|
|
jsTestLog('Enable replication on the SECONDARY ' + secondary.host);
|
|
|
|
|
assert.commandWorked(
|
|
|
|
|
secondary.getDB('admin').runCommand(
|
|
|
|
|
{configureFailPoint: 'rsSyncApplyStop', mode: 'off'}
|
|
|
|
|
),
|
|
|
|
|
'Failed to disable rsSyncApplyStop failpoint.'
|
|
|
|
|
);
|
2014-11-05 11:49:27 -05:00
|
|
|
|
2015-10-09 19:40:08 -04:00
|
|
|
jsTestLog("Wait for PRIMARY " + primary.host + " to completely step down.");
|
2015-12-10 10:21:51 -05:00
|
|
|
replSet.waitForState(primary, ReplSetTest.State.SECONDARY, secondaryCatchUpPeriodSecs * 1000);
|
2015-06-23 22:22:52 -04:00
|
|
|
var exitCode = stepDowner({checkExitSuccess: false});
|
|
|
|
|
assert.neq(0, exitCode, "expected replSetStepDown to close the shell's connection");
|
|
|
|
|
|
|
|
|
|
// The connection for the 'writer' may be closed due to the primary stepping down, or signaled
|
|
|
|
|
// by the main thread to quit.
|
|
|
|
|
writer({checkExitSuccess: false});
|
2015-10-09 19:40:08 -04:00
|
|
|
|
|
|
|
|
jsTestLog("Wait for SECONDARY " + secondary.host + " to become PRIMARY");
|
2015-12-10 10:21:51 -05:00
|
|
|
replSet.waitForState(secondary, ReplSetTest.State.PRIMARY, stepDownSecs * 1000);
|
2014-11-05 11:49:27 -05:00
|
|
|
})();
|