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 /src/mongo | |
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 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/count.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/group.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/exec/plan_stage.h | 3 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_cursor.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/query/explain.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/query/explain.h | 9 | ||||
-rw-r--r-- | src/mongo/db/query/new_find.cpp | 7 | ||||
-rw-r--r-- | src/mongo/s/cluster_explain.cpp | 12 |
10 files changed, 49 insertions, 35 deletions
diff --git a/src/mongo/db/commands/count.cpp b/src/mongo/db/commands/count.cpp index 62df3539934..8687a56c184 100644 --- a/src/mongo/db/commands/count.cpp +++ b/src/mongo/db/commands/count.cpp @@ -94,7 +94,8 @@ namespace mongo { scoped_ptr<PlanExecutor> exec(rawExec); - return Explain::explainStages(exec.get(), verbosity, out); + Explain::explainStages(exec.get(), verbosity, out); + return Status::OK(); } virtual bool run(OperationContext* txn, diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index d0194e9d1eb..abb5960135d 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -118,7 +118,8 @@ namespace mongo { scoped_ptr<PlanExecutor> exec(rawExec); // Got the execution tree. Explain it. - return Explain::explainStages(exec.get(), verbosity, out); + Explain::explainStages(exec.get(), verbosity, out); + return Status::OK(); } bool FindCmd::run(OperationContext* txn, diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp index 6f1a8a7153d..654ff73001b 100644 --- a/src/mongo/db/commands/group.cpp +++ b/src/mongo/db/commands/group.cpp @@ -206,7 +206,8 @@ namespace mongo { scoped_ptr<PlanExecutor> planExecutor(rawPlanExecutor); - return Explain::explainStages(planExecutor.get(), verbosity, out); + Explain::explainStages(planExecutor.get(), verbosity, out); + return Status::OK(); } } // namespace mongo diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index 2c4dc88feea..9719792e22c 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -227,7 +227,8 @@ namespace mongo { PlanExecutor* exec = updateExecutor.getPlanExecutor(); // Explain the plan tree. - return Explain::explainStages( exec, verbosity, out ); + Explain::explainStages( exec, verbosity, out ); + return Status::OK(); } else { invariant( BatchedCommandRequest::BatchType_Delete == _writeType ); @@ -266,7 +267,8 @@ namespace mongo { PlanExecutor* exec = deleteExecutor.getPlanExecutor(); // Explain the plan tree. - return Explain::explainStages( exec, verbosity, out ); + Explain::explainStages( exec, verbosity, out ); + return Status::OK(); } } diff --git a/src/mongo/db/exec/plan_stage.h b/src/mongo/db/exec/plan_stage.h index 6cfb91adf96..401b8abb527 100644 --- a/src/mongo/db/exec/plan_stage.h +++ b/src/mongo/db/exec/plan_stage.h @@ -141,6 +141,9 @@ namespace mongo { else if (NEED_TIME == state) { return "NEED_TIME"; } + else if (DEAD == state) { + return "DEAD"; + } else { verify(FAILURE == state); return "FAILURE"; diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index d2ac4cea71c..90c285faff8 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -158,7 +158,6 @@ namespace mongo { // Get planner-level explain info from the underlying PlanExecutor. BSONObjBuilder explainBuilder; - Status explainStatus(ErrorCodes::InternalError, ""); { const NamespaceString nss(_ns); AutoGetCollectionForRead autoColl(pExpCtx->opCtx, nss); @@ -166,9 +165,7 @@ namespace mongo { massert(17392, "No _exec. Were we disposed before explained?", _exec); _exec->restoreState(pExpCtx->opCtx); - explainStatus = Explain::explainStages(_exec.get(), - ExplainCommon::QUERY_PLANNER, - &explainBuilder); + Explain::explainStages(_exec.get(), ExplainCommon::QUERY_PLANNER, &explainBuilder); _exec->saveState(); } @@ -185,14 +182,9 @@ namespace mongo { out["fields"] = Value(_projection); // Add explain results from the query system into the agg explain output. - if (explainStatus.isOK()) { - BSONObj explainObj = explainBuilder.obj(); - invariant(explainObj.hasField("queryPlanner")); - out["queryPlanner"] = Value(explainObj["queryPlanner"]); - } - else { - out["planError"] = Value(explainStatus.toString()); - } + BSONObj explainObj = explainBuilder.obj(); + invariant(explainObj.hasField("queryPlanner")); + out["queryPlanner"] = Value(explainObj["queryPlanner"]); return Value(DOC(getSourceName() << out.freezeToValue())); } diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp index 6deb2c5909d..32d8eb2ce6a 100644 --- a/src/mongo/db/query/explain.cpp +++ b/src/mongo/db/query/explain.cpp @@ -554,9 +554,9 @@ namespace mongo { } // static - Status Explain::explainStages(PlanExecutor* exec, - ExplainCommon::Verbosity verbosity, - BSONObjBuilder* out) { + void Explain::explainStages(PlanExecutor* exec, + ExplainCommon::Verbosity verbosity, + BSONObjBuilder* out) { // // Step 1: run the stages as required by the verbosity level. // @@ -573,11 +573,9 @@ namespace mongo { } // If we need execution stats, then run the plan in order to gather the stats. + Status executePlanStatus = Status::OK(); if (verbosity >= ExplainCommon::EXEC_STATS) { - Status s = exec->executePlan(); - if (!s.isOK()) { - return s; - } + executePlanStatus = exec->executePlan(); } // @@ -605,6 +603,14 @@ namespace mongo { if (verbosity >= ExplainCommon::EXEC_STATS) { BSONObjBuilder execBob(out->subobjStart("executionStats")); + // If there is an execution error while running the query, the error is reported under + // the "executionStats" section and the explain as a whole succeeds. + execBob.append("executionSuccess", executePlanStatus.isOK()); + if (!executePlanStatus.isOK()) { + execBob.append("errorMessage", executePlanStatus.reason()); + execBob.append("errorCode", executePlanStatus.code()); + } + // Generate exec stats BSON for the winning plan. OperationContext* opCtx = exec->getOpCtx(); long long totalTimeMillis = opCtx->getCurOp()->elapsedMillis(); @@ -635,8 +641,6 @@ namespace mongo { } generateServerInfo(out); - - return Status::OK(); } // static diff --git a/src/mongo/db/query/explain.h b/src/mongo/db/query/explain.h index f76b8713a0e..31ef77f03bd 100644 --- a/src/mongo/db/query/explain.h +++ b/src/mongo/db/query/explain.h @@ -93,10 +93,13 @@ namespace mongo { * The explain information is generated with the level of detail specified by 'verbosity'. * * Does not take ownership of its arguments. + * + * If there is an error during the execution of the query, the error message and code are + * added to the "executionStats" section of the explain. */ - static Status explainStages(PlanExecutor* exec, - ExplainCommon::Verbosity verbosity, - BSONObjBuilder* out); + static void explainStages(PlanExecutor* exec, + ExplainCommon::Verbosity verbosity, + BSONObjBuilder* out); /** * Converts the stats tree 'stats' into a corresponding BSON object containing diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp index 89d724c4c30..f546dc4db19 100644 --- a/src/mongo/db/query/new_find.cpp +++ b/src/mongo/db/query/new_find.cpp @@ -613,12 +613,7 @@ namespace mongo { bb.skip(sizeof(QueryResult::Value)); BSONObjBuilder explainBob; - Status explainStatus = Explain::explainStages(exec.get(), - ExplainCommon::EXEC_ALL_PLANS, - &explainBob); - if (!explainStatus.isOK()) { - uasserted(18521, "Explain error: " + explainStatus.reason()); - } + Explain::explainStages(exec.get(), ExplainCommon::EXEC_ALL_PLANS, &explainBob); // Add the resulting object to the return buffer. BSONObj explainObj = explainBob.obj(); diff --git a/src/mongo/s/cluster_explain.cpp b/src/mongo/s/cluster_explain.cpp index a90d4baa9a2..f75c22e45fc 100644 --- a/src/mongo/s/cluster_explain.cpp +++ b/src/mongo/s/cluster_explain.cpp @@ -270,6 +270,18 @@ namespace mongo { BSONObj execStages = execStats["executionStages"].Obj(); singleShardBob.append("shardName", shardResults[i].shardTarget.getName()); + + // Append error-related fields, if present. + if (!execStats["executionSuccess"].eoo()) { + singleShardBob.append(execStats["executionSuccess"]); + } + if (!execStats["errorMessage"].eoo()) { + singleShardBob.append(execStats["errorMessage"]); + } + if (!execStats["errorCode"].eoo()) { + singleShardBob.append(execStats["errorCode"]); + } + appendIfRoom(&singleShardBob, execStages, "executionStages"); singleShardBob.doneFast(); |