/** * Tests that the shell helper db.currentOpCursor isn't constrained by the legacy currentOp server * command - ie. the result set isn't limited to 16MB and long operations aren't truncated. * * @tags: [ * uses_parallel_shell, * # This test uses currentOp to check whether an aggregate command is running. In replica set * # environments, because currentOp is run against the admin database it is routed to the * # primary, while the aggregate may be routed to a secondary. If currentOp is running on one * # node and the expected command is run on another, the latter will not show up in the * # currentOp results. * assumes_read_preference_unchanged, * no_selinux, * ] */ (function() { "use strict"; load("jstests/libs/fixture_helpers.js"); // for FixtureHelpers const coll = db.currentOp_cursor; coll.drop(); for (let i = 0; i < 3; i++) { assert.commandWorked(coll.insert({val: 1})); } // Test that db.currentOpCursor() returns an iterable cursor. let res = db.currentOpCursor(); assert(res.hasNext()); assert(res.next()); // Test that db.currentOp() interface does not change. res = db.currentOp(); assert("inprog" in res, "Result contains 'inprog' field"); assert("ok" in res, "Result contains 'ok' field"); // Attempting to access the fsyncLock field from the results throws with an error message. let error = assert.throws(() => res.fsyncLock); assert( /fsyncLock is no longer included in the currentOp shell helper, run db\.runCommand\({currentOp: 1}\) instead/ .test(error)); function shellOp() { function createLargeDoc() { let doc = {}; for (let i = 0; i < 100; i++) { doc[i] = "Testing testing 1 2 3..."; } return doc; } assert.commandFailedWithCode(db.runCommand({ aggregate: "currentOp_cursor", pipeline: [{ $addFields: { newVal: {$function: {args: [], body: "sleep(1000000)", lang: "js"}}, bigDoc: createLargeDoc() } }], comment: TestData.comment, cursor: {} }), ErrorCodes.Interrupted); } function startShellWithOp(comment) { TestData.comment = comment; const awaitShell = startParallelShell(shellOp); // Confirm that the operation has started in the parallel shell. assert.soon( function() { let aggRes = db.getSiblingDB("admin") .aggregate([ {$currentOp: {}}, {$match: {ns: "test.currentOp_cursor", "command.comment": TestData.comment}} ]) .toArray(); return aggRes.length >= 1; }, function() { return "Failed to find parallel shell operation in $currentOp output: " + tojson(db.currentOp()); }); return awaitShell; } // Test that the currentOp server command truncates long operations with a warning logged. const serverCommandTest = startShellWithOp("currentOp_server"); res = db.adminCommand({ currentOp: true, $and: [{"ns": "test.currentOp_cursor"}, {"command.comment": "currentOp_server"}] }); if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) { // Assert currentOp truncation behavior for each shard in the cluster. assert(res.inprog.length >= 1, res); res.inprog.forEach((result) => { assert.eq(result.op, "getmore", result); assert(result.cursor.originatingCommand.hasOwnProperty("$truncated"), result); }); } else { // Assert currentOp truncation behavior for unsharded collections. assert.eq(res.inprog.length, 1, res); assert.eq(res.inprog[0].op, "command", res); assert(res.inprog[0].command.hasOwnProperty("$truncated"), res); } const log = FixtureHelpers.getPrimaryForNodeHostingDatabase(db).adminCommand({getLog: "global"}); assert(/will be truncated/.test(log.log)); res.inprog.forEach((op) => { assert.commandWorked(db.killOp(op.opid)); }); serverCommandTest(); // Test that the db.currentOp() shell helper does not truncate ops. const shellHelperTest = startShellWithOp("currentOp_shell"); res = db.currentOp({"ns": "test.currentOp_cursor", "command.comment": "currentOp_shell"}); if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) { assert(res.inprog.length >= 1, res); res.inprog.forEach((result) => { assert.eq(result.op, "getmore", result); assert(!result.cursor.originatingCommand.hasOwnProperty("$truncated"), result); }); } else { assert.eq(res.inprog.length, 1, res); assert(!res.inprog[0].command.hasOwnProperty("$truncated"), res); } res.inprog.forEach((op) => { assert.commandWorked(db.killOp(op.opid)); }); shellHelperTest(); })();