var wait; var occasionally; var reconnect; var getLatestOp; var waitForAllMembers; var reconfig; var awaitOpTime; var startSetIfSupportsReadMajority; var waitUntilAllNodesCaughtUp; var updateConfigIfNotDurable; (function() { "use strict"; var count = 0; var w = 0; wait = function(f, msg) { w++; var n = 0; while (!f()) { if (n % 4 == 0) print("waiting " + w); if (++n == 4) { print("" + f); } if (n >= 200) { throw new Error('tried 200 times, giving up on ' + msg); } sleep(1000); } }; /** * Use this to do something once every 4 iterations. * *
     * for (i=0; i<1000; i++) {
     *   occasionally(function() { print("4 more iterations"); });
     * }
     * 
*/ occasionally = function(f, n) { var interval = n || 4; if (count % interval == 0) { f(); } count++; }; reconnect = function(a) { wait(function() { var db; try { // make this work with either dbs or connections if (typeof(a.getDB) == "function") { db = a.getDB('foo'); } else { db = a; } db.bar.stats(); if (jsTest.options().keyFile) { // SERVER-4241: Shell connections don't // re-authenticate on reconnect return jsTest.authenticate(db.getMongo()); } return true; } catch (e) { print(e); return false; } }); }; getLatestOp = function(server) { server.getDB("admin").getMongo().setSlaveOk(); var log = server.getDB("local")['oplog.rs']; var cursor = log.find({}).sort({'$natural': -1}).limit(1); if (cursor.hasNext()) { return cursor.next(); } return null; }; waitForAllMembers = function(master, timeout) { var failCount = 0; assert.soon(function() { var state = null; try { state = master.getSisterDB("admin").runCommand({replSetGetStatus: 1}); failCount = 0; } catch (e) { // Connection can get reset on replica set failover causing a socket exception print("Calling replSetGetStatus failed"); print(e); return false; } occasionally(function() { printjson(state); }, 10); for (var m in state.members) { if (state.members[m].state != 1 && // PRIMARY state.members[m].state != 2 && // SECONDARY state.members[m].state != 7) { // ARBITER return false; } } printjson(state); return true; }, "not all members ready", timeout || 60000); print("All members are now in state PRIMARY, SECONDARY, or ARBITER"); }; reconfig = function(rs, config, force) { "use strict"; var admin = rs.getPrimary().getDB("admin"); var e; var master; try { assert.commandWorked(admin.runCommand({replSetReconfig: config, force: force})); } catch (e) { if (tojson(e).indexOf("error doing query: failed") < 0) { throw e; } } var master = rs.getPrimary().getDB("admin"); waitForAllMembers(master); return master; }; awaitOpTime = function(node, opTime) { var ts, ex; assert.soon( function() { try { // The following statement extracts the timestamp field from the most recent // element of // the oplog, and stores it in "ts". ts = node.getDB("local")['oplog.rs'] .find({}) .sort({'$natural': -1}) .limit(1) .next() .ts; if ((ts.t == opTime.t) && (ts.i == opTime.i)) { return true; } ex = null; return false; } catch (ex) { return false; } }, function() { var message = "Node " + node + " only reached optime " + tojson(ts) + " not " + tojson(opTime); if (ex) { message += "; last attempt failed with exception " + tojson(ex); } return message; }); }; /** * Uses the results of running replSetGetStatus against an arbitrary replset node to wait until * all nodes in the set are replicated through the same optime. * 'rs' is an array of connections to replica set nodes. This function is useful when you * don't have a ReplSetTest object to use, otherwise ReplSetTest.awaitReplication is preferred. */ waitUntilAllNodesCaughtUp = function(rs, timeout) { var rsStatus; var firstConflictingIndex; var ot; var otherOt; assert.soon( function() { rsStatus = rs[0].adminCommand('replSetGetStatus'); if (rsStatus.ok != 1) { return false; } assert.eq(rs.length, rsStatus.members.length, tojson(rsStatus)); ot = rsStatus.members[0].optime; for (var i = 1; i < rsStatus.members.length; ++i) { otherOt = rsStatus.members[i].optime; if (bsonWoCompare({ts: otherOt.ts}, {ts: ot.ts}) || bsonWoCompare({t: otherOt.t}, {t: ot.t})) { firstConflictingIndex = i; return false; } } return true; }, function() { return "Optimes of members 0 (" + tojson(ot) + ") and " + firstConflictingIndex + " (" + tojson(otherOt) + ") are different in " + tojson(rsStatus); }, timeout); }; /** * Starts each node in the given replica set if the storage engine supports readConcern *'majority'. * Returns true if the replica set was started successfully and false otherwise. * * @param replSetTest - The instance of {@link ReplSetTest} to start * @param options - The options passed to {@link ReplSetTest.startSet} */ startSetIfSupportsReadMajority = function(replSetTest, options) { try { replSetTest.startSet(options); } catch (e) { var conn = MongoRunner.runMongod(); if (!conn.getDB("admin").serverStatus().storageEngine.supportsCommittedReads) { MongoRunner.stopMongod(conn); return false; } throw e; } return true; }; /** * Changes the replica set config if journaling/ephemal storage engine to set * writeConcernMajorityJournalDefault to false. */ updateConfigIfNotDurable = function(config) { var runningWithoutJournaling = TestData.noJournal || 0 != ["inMemory", "ephemeralForTest"].filter((a) => a == TestData.storageEngine).length; if (runningWithoutJournaling) { config.writeConcernMajorityJournalDefault = false; } return config; }; }());