// test rollback in replica sets // try running as : // // mongo --nodb rollback.js | tee out | grep -v ^m31 // var debugging = 0; function pause(s) { print(s); while (debugging) { sleep(3000); print(s); } } function deb(obj) { if( debugging ) { print("\n\n\n" + obj + "\n\n"); } } w = 0; function wait(f) { w++; var n = 0; while (!f()) { if( n % 4 == 0 ) print("rollback.js waiting " + w); if (++n == 4) { print("" + f); } sleep(1000); } } doTest = function (signal) { var replTest = new ReplSetTest({ name: 'unicomplex', nodes: 3 }); var nodes = replTest.nodeList(); //print(tojson(nodes)); var conns = replTest.startSet(); var r = replTest.initiate({ "_id": "unicomplex", "members": [ { "_id": 0, "host": nodes[0] }, { "_id": 1, "host": nodes[1] }, { "_id": 2, "host": nodes[2], arbiterOnly: true}] }); // Make sure we have a master var master = replTest.getMaster(); a_conn = conns[0]; A = a_conn.getDB("admin"); b_conn = conns[1]; a_conn.setSlaveOk(); b_conn.setSlaveOk(); B = b_conn.getDB("admin"); assert(master == conns[0], "conns[0] assumed to be master"); assert(a_conn == master); //deb(master); // Make sure we have an arbiter assert.soon(function () { res = conns[2].getDB("admin").runCommand({ replSetGetStatus: 1 }); return res.myState == 7; }, "Arbiter failed to initialize."); // Wait for initial replication var a = a_conn.getDB("foo"); var b = b_conn.getDB("foo"); /* force the oplog to roll */ if (new Date() % 2 == 0) { print("ROLLING OPLOG AS PART OF TEST (we only do this sometimes)"); var pass = 1; var first = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0]; a.roll.insert({ x: 1 }); while (1) { for (var i = 0; i < 10000; i++) a.roll.update({}, { $inc: { x: 1} }); var op = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0]; if (tojson(op.h) != tojson(first.h)) { printjson(op); printjson(first); break; } pass++; a.getLastError(2); // unlikely secondary isn't keeping up, but let's avoid possible intermittent issues with that. } print("PASSES FOR OPLOG ROLL: " + pass); } else { print("NO ROLL"); } a.bar.insert({ q: 1, a: "foo" }); a.bar.insert({ q: 2, a: "foo", x: 1 }); a.bar.insert({ q: 3, bb: 9, a: "foo" }); assert(a.bar.count() == 3, "t.count"); // wait for secondary to get this data wait(function () { return b.bar.count() == 3; }); A.runCommand({ replSetTest: 1, blind: true }); wait(function () { return B.isMaster().ismaster; }); b.bar.insert({ q: 4 }); b.bar.insert({ q: 5 }); b.bar.insert({ q: 6 }); assert(b.bar.count() == 6, "u.count"); // a should not have the new data as it was in blind state. B.runCommand({ replSetTest: 1, blind: true }); A.runCommand({ replSetTest: 1, blind: false }); wait(function () { return !B.isMaster().ismaster; }); wait(function () { return A.isMaster().ismaster; }); assert(a.bar.count() == 3, "t is 3"); a.bar.insert({ q: 7 }); a.bar.insert({ q: 8 }); { assert(a.bar.count() == 5); var x = a.bar.find().toArray(); assert(x[0].q == 1, '1'); assert(x[1].q == 2, '2'); assert(x[2].q == 3, '3'); assert(x[3].q == 7, '7'); assert(x[4].q == 8, '8'); } // A is 1 2 3 7 8 // B is 1 2 3 4 5 6 // bring B back online B.runCommand({ replSetTest: 1, blind: false }); wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; }); // everyone is up here... assert(A.isMaster().ismaster || A.isMaster().secondary, "A up"); assert(B.isMaster().ismaster || B.isMaster().secondary, "B up"); friendlyEqual(a.bar.find().sort({ _id: 1 }).toArray(), b.bar.find().sort({ _id: 1 }).toArray(), "server data sets do not match"); pause("rollback.js SUCCESS"); replTest.stopSet(signal); } print("rollback.js"); doTest( 15 );