174 lines
4.9 KiB
JavaScript
174 lines
4.9 KiB
JavaScript
// Test killop applied to m/r operations and child ops of m/r operations.
|
|
|
|
t = db.jstests_mr_killop;
|
|
t.drop();
|
|
t2 = db.jstests_mr_killop_out;
|
|
t2.drop();
|
|
|
|
function debug(x) {
|
|
// printjson( x );
|
|
}
|
|
|
|
/** @return op code for map reduce op created by spawned shell, or that op's child */
|
|
function op(childLoop) {
|
|
p = db.currentOp().inprog;
|
|
debug(p);
|
|
for (var i in p) {
|
|
var o = p[i];
|
|
// Identify a map/reduce or where distinct operation by its collection, whether or not
|
|
// it is currently active.
|
|
if (childLoop) {
|
|
if ((o.active || o.waitingForLock) && o.query && o.query.query &&
|
|
o.query.query.$where && o.query.distinct == "jstests_mr_killop") {
|
|
return o.opid;
|
|
}
|
|
} else {
|
|
if ((o.active || o.waitingForLock) && o.query && o.query.mapreduce &&
|
|
o.query.mapreduce == "jstests_mr_killop") {
|
|
return o.opid;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Run one map reduce with the specified parameters in a parallel shell, kill the
|
|
* map reduce op or its child op with killOp, and wait for the map reduce op to
|
|
* terminate.
|
|
* @param childLoop - if true, a distinct $where op is killed rather than the map reduce op.
|
|
* This is necessay for a child distinct $where of a map reduce op because child
|
|
* ops currently mask parent ops in currentOp.
|
|
*/
|
|
function testOne(map, reduce, finalize, scope, childLoop, wait) {
|
|
debug("testOne - map = " + tojson(map) + "; reduce = " + tojson(reduce) + "; finalize = " +
|
|
tojson(finalize) + "; scope = " + tojson(scope) + "; childLoop = " + childLoop +
|
|
"; wait = " + wait);
|
|
|
|
t.drop();
|
|
t2.drop();
|
|
// Ensure we have 2 documents for the reduce to run
|
|
t.save({a: 1});
|
|
t.save({a: 1});
|
|
|
|
spec = {mapreduce: "jstests_mr_killop", out: "jstests_mr_killop_out", map: map, reduce: reduce};
|
|
if (finalize) {
|
|
spec["finalize"] = finalize;
|
|
}
|
|
if (scope) {
|
|
spec["scope"] = scope;
|
|
}
|
|
|
|
// Windows shell strips all double quotes from command line, so use
|
|
// single quotes.
|
|
stringifiedSpec = tojson(spec).toString().replace(/\n/g, ' ').replace(/\"/g, "\'");
|
|
|
|
// The assert below won't be caught by this test script, but it will cause error messages
|
|
// to be printed.
|
|
var awaitShell =
|
|
startParallelShell("assert.commandWorked( db.runCommand( " + stringifiedSpec + " ) );");
|
|
|
|
if (wait) {
|
|
sleep(2000);
|
|
}
|
|
|
|
o = null;
|
|
assert.soon(function() {
|
|
o = op(childLoop);
|
|
return o != -1;
|
|
});
|
|
|
|
res = db.killOp(o);
|
|
debug("did kill : " + tojson(res));
|
|
|
|
// When the map reduce op is killed, the spawned shell will exit
|
|
var exitCode = awaitShell({checkExitSuccess: false});
|
|
assert.neq(0,
|
|
exitCode,
|
|
"expected shell to exit abnormally due to map-reduce execution being terminated");
|
|
debug("parallel shell completed");
|
|
|
|
assert.eq(-1, op(childLoop));
|
|
}
|
|
|
|
/** Test using wait and non wait modes */
|
|
function test(map, reduce, finalize, scope, childLoop) {
|
|
debug(" Non wait mode");
|
|
testOne(map, reduce, finalize, scope, childLoop, false);
|
|
|
|
debug(" Wait mode");
|
|
testOne(map, reduce, finalize, scope, childLoop, true);
|
|
}
|
|
|
|
/** Test looping in map and reduce functions */
|
|
function runMRTests(loop, childLoop) {
|
|
debug(" Running MR test - loop map function. no scope ");
|
|
test(loop, // map
|
|
function(k, v) {
|
|
return v[0];
|
|
}, // reduce
|
|
null, // finalize
|
|
null, // scope
|
|
childLoop);
|
|
|
|
debug(" Running MR test - loop reduce function ");
|
|
test(
|
|
function() {
|
|
emit(this.a, 1);
|
|
}, // map
|
|
loop, // reduce
|
|
null, // finalize
|
|
null, // scope
|
|
childLoop);
|
|
|
|
debug(" Running finalization test - loop map function. with scope ");
|
|
test(
|
|
function() {
|
|
loop();
|
|
}, // map
|
|
function(k, v) {
|
|
return v[0];
|
|
}, // reduce
|
|
null, // finalize
|
|
{loop: loop}, // scope
|
|
childLoop);
|
|
}
|
|
|
|
/** Test looping in finalize function */
|
|
function runFinalizeTests(loop, childLoop) {
|
|
debug(" Running finalization test - no scope ");
|
|
test(
|
|
function() {
|
|
emit(this.a, 1);
|
|
}, // map
|
|
function(k, v) {
|
|
return v[0];
|
|
}, // reduce
|
|
loop, // finalize
|
|
null, // scope
|
|
childLoop);
|
|
|
|
debug(" Running finalization test - with scope ");
|
|
test(
|
|
function() {
|
|
emit(this.a, 1);
|
|
}, // map
|
|
function(k, v) {
|
|
return v[0];
|
|
}, // reduce
|
|
function(a, b) {
|
|
loop();
|
|
}, // finalize
|
|
{loop: loop}, // scope
|
|
childLoop);
|
|
}
|
|
|
|
// Run inside server. No access to debug().
|
|
var loop = function() {
|
|
while (1) {
|
|
sleep(1000);
|
|
}
|
|
};
|
|
runMRTests(loop, false);
|
|
runFinalizeTests(loop, false);
|