summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-10-16 10:49:36 -0400
committerDavid Storch <david.storch@10gen.com>2014-10-29 14:07:47 -0400
commit32a5c787a2545f27f0d1aeeb43764c40ae48e32b (patch)
tree2122e46f9c1ec50c68e9f01b0e3e0cf5b819de4b /src/mongo
parent205756215a42aa6abf8caca6577e4148833b50c5 (diff)
downloadmongo-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.cpp3
-rw-r--r--src/mongo/db/commands/find_cmd.cpp3
-rw-r--r--src/mongo/db/commands/group.cpp3
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp6
-rw-r--r--src/mongo/db/exec/plan_stage.h3
-rw-r--r--src/mongo/db/pipeline/document_source_cursor.cpp16
-rw-r--r--src/mongo/db/query/explain.cpp22
-rw-r--r--src/mongo/db/query/explain.h9
-rw-r--r--src/mongo/db/query/new_find.cpp7
-rw-r--r--src/mongo/s/cluster_explain.cpp12
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();