// Ensure writes do not prevent a node from Stepping down // 1. Start up a 3 node set (1 arbiter). // 2. Isolate the SECONDARY. // 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. // 5. Once a write is blocked, de-isolate the SECONDARY. // 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}]}); jsTestLog("isolate one node"); replSet.bridge(); replSet.partition(1,0); replSet.partition(1,2); replSet.waitForState(replSet.nodes[0], replSet.PRIMARY, 60 * 1000); var primary = replSet.getPrimary(); var secondary = replSet.getSecondary(); assert.eq(primary.host, nodes[0], "primary assumed to be node 0"); 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)); var cmd = "db.getSiblingDB('admin').runCommand({replSetStepDown: 60, " + "secondaryCatchUpPeriodSecs: 60});"; var stepDowner = startParallelShell(cmd, primary.port); 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; }, "global shared lock not acquired"); jsTestLog("do a write and wait for it to be waiting for a lock"); var updateCmd = function() { while (true) { var res = db.getSiblingDB("stepDownWithLongWait").foo.update({}, {$inc: {x: 1}}); assert.writeOK(res); if (res.nModified === 0) { // main thread signaled update thread to exit by deleting the doc it's updating quit(0); } } }; 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; }, "write failed to block on global lock"); jsTestLog("bring back the SECONDARY and wait for it become PRIMARY"); replSet.unPartition(1,0); replSet.unPartition(1,2); replSet.waitForState(secondary, replSet.PRIMARY, 30000); jsTestLog("signal update thread to exit"); var newPrimary = replSet.getPrimary(); assert.writeOK(newPrimary.getDB(name).foo.remove({})); stepDowner(); writer(); })();