diff options
author | David Storch <david.storch@10gen.com> | 2014-10-16 10:49:36 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-10-29 14:07:47 -0400 |
commit | 32a5c787a2545f27f0d1aeeb43764c40ae48e32b (patch) | |
tree | 2122e46f9c1ec50c68e9f01b0e3e0cf5b819de4b /jstests/core/explain_execution_error.js | |
parent | 205756215a42aa6abf8caca6577e4148833b50c5 (diff) | |
download | mongo-32a5c787a2545f27f0d1aeeb43764c40ae48e32b.tar.gz |
SERVER-15527 explain should report planner info and exec stats when query execution fails
This also changes the error behavior of explain so that the explain command succeeds as long
as it has provided valid output, even if the underlying operation failed.
Diffstat (limited to 'jstests/core/explain_execution_error.js')
-rw-r--r-- | jstests/core/explain_execution_error.js | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/jstests/core/explain_execution_error.js b/jstests/core/explain_execution_error.js new file mode 100644 index 00000000000..280e4e3250d --- /dev/null +++ b/jstests/core/explain_execution_error.js @@ -0,0 +1,154 @@ +// Test that even when the execution of a query fails, explain reports query +// planner information. + +var t = db.explain_execution_error; +t.drop(); + +var result; + +/** + * Asserts that explain reports an error in its execution stats section. + */ +function assertExecError(explain) { + var errorObj; + + var execStats = explain.executionStats; + if (execStats.executionStages.stage == "SINGLE_SHARD") { + errorObj = execStats.executionStages.shards[0]; + } + else { + errorObj = execStats; + } + + assert.eq(false, errorObj.executionSuccess); + assert("errorMessage" in errorObj); + assert("errorCode" in errorObj); +} + +/** + * Asserts that explain reports success in its execution stats section. + */ +function assertExecSuccess(explain) { + var errorObj; + + var execStats = explain.executionStats; + if (execStats.executionStages.stage == "SINGLE_SHARD") { + errorObj = execStats.executionStages.shards[0]; + } + else { + errorObj = execStats; + } + + assert.eq(true, errorObj.executionSuccess); + assert(!("errorMessage" in errorObj)); + assert(!("errorCode" in errorObj)); +} + +// Make a string that exceeds 1 MB. +var bigStr = "x"; +while (bigStr.length < (1024 * 1024)) { + bigStr += bigStr; +} + +// Make a collection that is about 40 MB. +for (var i = 0; i < 40; i++) { + assert.writeOK(t.insert({a: bigStr, b: 1, c: i})); +} + +// A query which sorts the whole collection by "b" should throw an error due to hitting the +// memory limit for sort. +assert.throws(function() { + t.find({a: {$exists: true}}).sort({b: 1}).itcount(); +}); + +// Explain of this query should succeed at query planner verbosity. +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {a: {$exists: true}}, + sort: {b: 1} + }, + verbosity: "queryPlanner" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); + +// Explaining the same query at execution stats verbosity should succeed, but indicate that the +// underlying operation failed. +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {a: {$exists: true}}, + sort: {b: 1} + }, + verbosity: "executionStats" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); +assert("executionStats" in result); +assertExecError(result); + +// The underlying operation should also report a failure at allPlansExecution verbosity. +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {a: {$exists: true}}, + sort: {b: 1} + }, + verbosity: "allPlansExecution" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); +assert("executionStats" in result); +assert("allPlansExecution" in result.executionStats); +assertExecError(result); + +// Now we introduce two indices. One provides the requested sort order, and +// the other does not. +t.ensureIndex({b: 1}); +t.ensureIndex({c: 1}); + +// The query should no longer fail with a memory limit error because the planner can obtain +// the sort by scanning an index. +assert.eq(40, t.find({c: {$lt: 40}}).sort({b: 1}).itcount()); + +// The explain should succeed at all verbosity levels because the query itself succeeds. +// First test "queryPlanner" verbosity. +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {c: {$lt: 40}}, + sort: {b: 1} + }, + verbosity: "queryPlanner" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); + +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {c: {$lt: 40}}, + sort: {b: 1} + }, + verbosity: "executionStats" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); +assert("executionStats" in result); +assertExecSuccess(result); + +// We expect allPlansExecution verbosity to show execution stats for both candidate plans. +result = db.runCommand({ + explain: { + find: t.getName(), + filter: {c: {$lt: 40}}, + sort: {b: 1} + }, + verbosity: "allPlansExecution" +}); +assert.commandWorked(result); +assert("queryPlanner" in result); +assert("executionStats" in result); +assert("allPlansExecution" in result.executionStats); +assertExecSuccess(result); |