summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Wahlin <james.wahlin@10gen.com>2017-01-04 08:54:22 -0500
committerJames Wahlin <james.wahlin@10gen.com>2017-01-18 12:34:50 -0500
commit09e64473f6989e9338d11d0e702ceadf1050b31c (patch)
tree6ffb099ce8b2a5c94738fecea7d8cd8e9eb55e96
parenta10fb3c03e6770e94df1ffed7fc50457115aca78 (diff)
downloadmongo-09e64473f6989e9338d11d0e702ceadf1050b31c.tar.gz
SERVER-27465 rewrite killop.js using setYieldAllLocksHang failpoint
(cherry picked from commit 2ead884968ba7564e9cedf5e8b0e588ad5c031de)
-rw-r--r--jstests/core/killop.js86
-rw-r--r--jstests/libs/parallelTester.js1
-rw-r--r--jstests/noPassthrough/killop.js71
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();
+})();