2015-09-23 22:36:21 -04:00
|
|
|
/**
|
|
|
|
|
* This test will ensure that a failed a batch apply will become consistent only when passing
|
|
|
|
|
* the end boundary (minvalid) in subsequent applies.
|
|
|
|
|
*
|
|
|
|
|
* To do this we:
|
|
|
|
|
* -- Set minvalid manually on primary (node0) way ahead (5 minutes)
|
|
|
|
|
* -- Restart primary (node0)
|
|
|
|
|
* -- Ensure restarted primary (node0) comes up in recovering
|
|
|
|
|
* -- Ensure node0 replicates a batch, and keeps the old minvalid
|
|
|
|
|
* -- Success!
|
2015-11-19 14:01:59 -05:00
|
|
|
*
|
|
|
|
|
* This test requires persistence to test that a restarted primary will stay in the RECOVERING state
|
|
|
|
|
* when minvalid is set to the future. An ephemeral storage engine will not have a minvalid after
|
|
|
|
|
* restarting, so will initial sync in this scenario, invalidating the test.
|
|
|
|
|
* @tags: [requires_persistence]
|
2015-09-23 22:36:21 -04:00
|
|
|
*/
|
|
|
|
|
(function() {
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
function tsToDate(ts) {
|
|
|
|
|
return new Date(ts.getTime() * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var replTest = new ReplSetTest({name: "apply_batch_only_goes_forward", nodes: 3});
|
|
|
|
|
|
|
|
|
|
var nodes = replTest.startSet();
|
|
|
|
|
replTest.initiate();
|
2015-11-25 11:20:43 -05:00
|
|
|
var master = replTest.getPrimary();
|
2015-09-23 22:36:21 -04:00
|
|
|
var mTest = master.getDB("test");
|
|
|
|
|
var mLocal = master.getDB("local");
|
|
|
|
|
var mMinvalid = mLocal["replset.minvalid"];
|
|
|
|
|
|
|
|
|
|
var slave = replTest.getSecondary();
|
|
|
|
|
var sTest = slave.getDB("test");
|
|
|
|
|
var sLocal = slave.getDB("local");
|
|
|
|
|
var sMinvalid = sLocal["replset.minvalid"];
|
|
|
|
|
var stepDownSecs = 30;
|
2015-10-06 12:45:40 -04:00
|
|
|
var stepDownCmd = {replSetStepDown: stepDownSecs, force: true};
|
2015-09-23 22:36:21 -04:00
|
|
|
|
|
|
|
|
// Write op
|
2015-10-06 12:45:40 -04:00
|
|
|
assert.writeOK(mTest.foo.save({}, {writeConcern: {w: 3}}));
|
2015-12-10 10:21:51 -05:00
|
|
|
replTest.waitForState(slave, ReplSetTest.State.SECONDARY, 30000);
|
2015-10-06 12:45:40 -04:00
|
|
|
assert.writeOK(mTest.foo.save({}, {writeConcern: {w: 3}}));
|
2015-09-23 22:36:21 -04:00
|
|
|
|
|
|
|
|
// Set minvalid to something far in the future for the current primary, to simulate recovery.
|
|
|
|
|
// Note: This is so far in the future (5 days) that it will never become secondary.
|
|
|
|
|
var farFutureTS = new Timestamp(Math.floor(new Date().getTime()/1000) +
|
|
|
|
|
(60 * 60 * 24 * 5 /* in five days*/), 0);
|
2015-10-06 12:45:40 -04:00
|
|
|
var rsgs = assert.commandWorked(mLocal.adminCommand("replSetGetStatus"));
|
|
|
|
|
var primaryOpTime = rsgs.members.filter( function (member) {
|
|
|
|
|
return member.self;}
|
|
|
|
|
)[0].optime;
|
|
|
|
|
jsTest.log("future TS: " + tojson(farFutureTS) + ", date:" + tsToDate(farFutureTS));
|
|
|
|
|
// We do an update in case there is a minvalid document on the primary already.
|
|
|
|
|
// If the doc doesn't exist then upsert:true will create it, and the writeConcern ensures
|
|
|
|
|
// that update returns details of the write, like whether an update or insert was performed.
|
|
|
|
|
printjson(assert.writeOK(mMinvalid.update({},
|
|
|
|
|
{ ts: farFutureTS,
|
|
|
|
|
t: NumberLong(-1),
|
|
|
|
|
begin: primaryOpTime},
|
|
|
|
|
{ upsert: true, writeConcern: {w: 1}})));
|
2015-09-23 22:36:21 -04:00
|
|
|
|
|
|
|
|
jsTest.log("restart primary");
|
|
|
|
|
replTest.restart(master);
|
|
|
|
|
printjson(sLocal.adminCommand("isMaster"));
|
2015-12-10 10:21:51 -05:00
|
|
|
replTest.waitForState(master, ReplSetTest.State.RECOVERING, 90000);
|
2015-09-23 22:36:21 -04:00
|
|
|
|
|
|
|
|
// Slave is now master... so do a write to get a minvalid entry on the secondary.
|
2015-11-25 11:20:43 -05:00
|
|
|
assert.writeOK(replTest.getPrimary().getDB("test").foo.save({}, {writeConcern: {w: 3}}));
|
2015-09-23 22:36:21 -04:00
|
|
|
|
|
|
|
|
assert.soon(function() {
|
|
|
|
|
var mv;
|
|
|
|
|
try {mv = mMinvalid.findOne();} catch (e) { return false; }
|
|
|
|
|
var msg = "ts !=, " + farFutureTS +
|
|
|
|
|
"(" + tsToDate(farFutureTS) + "), mv:" + tojson(mv) + " - " + tsToDate(mv.ts);
|
|
|
|
|
assert.eq(farFutureTS, mv.ts, msg);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Shut down the set and finish the test.
|
|
|
|
|
replTest.stopSet();
|
2015-11-19 14:01:59 -05:00
|
|
|
})();
|