diff options
author | James Wahlin <james.wahlin@10gen.com> | 2017-01-04 08:54:22 -0500 |
---|---|---|
committer | James Wahlin <james.wahlin@10gen.com> | 2017-01-18 12:34:50 -0500 |
commit | 09e64473f6989e9338d11d0e702ceadf1050b31c (patch) | |
tree | 6ffb099ce8b2a5c94738fecea7d8cd8e9eb55e96 | |
parent | a10fb3c03e6770e94df1ffed7fc50457115aca78 (diff) | |
download | mongo-09e64473f6989e9338d11d0e702ceadf1050b31c.tar.gz |
SERVER-27465 rewrite killop.js using setYieldAllLocksHang failpoint
(cherry picked from commit 2ead884968ba7564e9cedf5e8b0e588ad5c031de)
-rw-r--r-- | jstests/core/killop.js | 86 | ||||
-rw-r--r-- | jstests/libs/parallelTester.js | 1 | ||||
-rw-r--r-- | jstests/noPassthrough/killop.js | 71 |
3 files changed, 71 insertions, 87 deletions
diff --git a/jstests/core/killop.js b/jstests/core/killop.js deleted file mode 100644 index 845e60bb74f..00000000000 --- a/jstests/core/killop.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Basic test of killop functionality. - * - * Theory of operation: Creates two operations that will take a long time, sends killop for those - * operations, and then attempts to infer that the operations died because of killop, and not for - * some other reason. - * - * NOTES: - * The long operations are count({ $where: function() { while (1) { sleep(500); } } }). These - * operations do not terminate until the server determines that they've spent too much time in JS - * execution, typically after 30 seconds of wall clock time have passed. For these operations to - * take a long time, the counted collection must not be empty; hence an initial write to the - * collection is required. - */ -(function() { - 'use strict'; - - if (jsTest.options().storageEngine === "mmapv1" && db.isMaster().msg === "isdbgrid") { - // SERVER-10747 MMAPv1's journal thread can block behind a long-running and non-yielding - // $where operations. This causes subsequent operations on the collection, such as - // setShardVersion, to block behind MMAPv1's journal thread. We therefore cannot expect - // to always be able to see *both* count operations running on a shard at the same time. - jsTest.log("Skipping test when running in a sharded cluster with mmapv1 shards"); - return; - } - - var t = db.jstests_killop; - t.save({x: 1}); - - /** - * This function filters for the operations that we're looking for, based on their state and - * the contents of their query object. - */ - function findRelevantOps(curops) { - var ids = []; - for (var i in curops) { - var o = curops[i]; - // We *can't* check for ns, b/c it's not guaranteed to be there unless the query is - // active, which it may not be in our polling cycle - particularly b/c we sleep every - // second in both the query and the assert - if ((o.active || o.waitingForLock) && o.query && o.query.query && - o.query.query.$where && o.query.count == "jstests_killop") { - ids.push(o.opid); - } - } - return ids; - } - - var countWithWhereOp = - 'db.jstests_killop.count({ $where: function() { while (1) { sleep(500); } } });'; - - jsTestLog("Starting long-running $where operation"); - var s1 = startParallelShell(countWithWhereOp); - var s2 = startParallelShell(countWithWhereOp); - - jsTestLog("Finding ops in currentOp() output"); - var allOps; - var relevantOps = []; - assert.soon( - function() { - allOps = db.currentOp().inprog; - relevantOps = findRelevantOps(allOps); - return relevantOps.length == 2; - }, - function() { - return tojson(allOps); - }, - 60000); - - var start = new Date(); - jsTestLog("Killing ops"); - db.killOp(relevantOps[0]); - db.killOp(relevantOps[1]); - - jsTestLog("Waiting for ops to terminate"); - [s1, s2].forEach(function(awaitShell) { - var exitCode = awaitShell({checkExitSuccess: false}); - assert.neq( - 0, exitCode, "expected shell to exit abnormally due to JS execution being terminated"); - }); - - // don't want to pass if timeout killed the js function. - var end = new Date(); - var diff = end - start; - assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff); -})(); diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js index ae29218b546..672fa4a97b4 100644 --- a/jstests/libs/parallelTester.js +++ b/jstests/libs/parallelTester.js @@ -161,7 +161,6 @@ if (typeof _threadInject != "undefined") { "indexh.js", "evald.js", "evalf.js", - "killop.js", "run_program1.js", "notablescan.js", "dropdb_race.js", diff --git a/jstests/noPassthrough/killop.js b/jstests/noPassthrough/killop.js new file mode 100644 index 00000000000..5181afb089b --- /dev/null +++ b/jstests/noPassthrough/killop.js @@ -0,0 +1,71 @@ +// Confirms basic killOp execution via mongod and mongos. + +(function() { + "use strict"; + + const dbName = "killop"; + const collName = "test"; + + // 'conn' is a connection to either a mongod when testing a replicaset or a mongos when testing + // a sharded cluster. 'shardConn' is a connection to the mongod we enable failpoints on. + function runTest(conn, shardConn) { + const db = conn.getDB(dbName); + assert.commandWorked(db.dropDatabase()); + assert.writeOK(db.getCollection(collName).insert({x: 1})); + + assert.commandWorked( + shardConn.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1})); + assert.commandWorked(shardConn.adminCommand( + {"configureFailPoint": "setYieldAllLocksHang", "mode": "alwaysOn"})); + + const queryToKill = "assert.commandWorked(db.getSiblingDB('" + dbName + + "').runCommand({find: '" + collName + "', filter: {x: 1}}));"; + const awaitShell = startParallelShell(queryToKill, conn.port); + let opId; + + assert.soon( + function() { + const result = + db.currentOp({"ns": dbName + "." + collName, "query.filter": {x: 1}}); + assert.commandWorked(result); + if (result.inprog.length === 1) { + opId = result.inprog[0].opid; + return true; + } + + return false; + }, + function() { + return "Failed to find operation in currentOp() output: " + tojson(db.currentOp()); + }); + + assert.commandWorked(db.killOp(opId)); + + let result = db.currentOp({"ns": dbName + "." + collName, "query.filter": {x: 1}}); + assert.commandWorked(result); + assert(result.inprog.length === 1, tojson(db.currentOp())); + assert(result.inprog[0].hasOwnProperty("killPending")); + assert.eq(true, result.inprog[0].killPending); + + assert.commandWorked( + shardConn.adminCommand({"configureFailPoint": "setYieldAllLocksHang", "mode": "off"})); + + const exitCode = awaitShell({checkExitSuccess: false}); + assert.neq(0, exitCode, "Expected shell to exit with failure due to operation kill"); + + result = db.currentOp({"ns": dbName + "." + collName, "query.filter": {x: 1}}); + assert.commandWorked(result); + assert(result.inprog.length === 0, tojson(db.currentOp())); + } + + const st = new ShardingTest({shards: 1, rs: {nodes: 1}, mongos: 1}); + const shardConn = st.rs0.getPrimary(); + + // Test killOp against mongod. + runTest(shardConn, shardConn); + + // Test killOp against mongos. + runTest(st.s, shardConn); + + st.stop(); +})(); |