diff options
author | David Storch <david.storch@10gen.com> | 2015-09-03 13:07:08 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2015-09-03 19:55:59 -0400 |
commit | 7a59ba6da674462e7f86a3a7111d58b0721a4138 (patch) | |
tree | 279879021e23ee636f2235d368bfbc9f090ef008 /src | |
parent | 47ea04eab5c554fbbc7a9d4945c5c9850aeed2ac (diff) | |
download | mongo-7a59ba6da674462e7f86a3a7111d58b0721a4138.tar.gz |
SERVER-20267 use the explain command path to answer OP_QUERY with $explain on mongos
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/dbmessage.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/dbmessage.h | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_cmd.cpp | 31 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 33 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.h | 20 | ||||
-rw-r--r-- | src/mongo/s/strategy.cpp | 31 |
6 files changed, 90 insertions, 29 deletions
diff --git a/src/mongo/db/dbmessage.cpp b/src/mongo/db/dbmessage.cpp index b1e6a245c28..eb50ecb063a 100644 --- a/src/mongo/db/dbmessage.cpp +++ b/src/mongo/db/dbmessage.cpp @@ -172,7 +172,7 @@ T DbMessage::readAndAdvance() { void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, - void* data, + const void* data, int size, int nReturned, int startingFrom, diff --git a/src/mongo/db/dbmessage.h b/src/mongo/db/dbmessage.h index 73c30f09bac..aa74fd59ffb 100644 --- a/src/mongo/db/dbmessage.h +++ b/src/mongo/db/dbmessage.h @@ -327,7 +327,7 @@ struct DbResponse { void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, - void* data, + const void* data, int size, int nReturned, int startingFrom = 0, diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 68cd2c00953..937515d17c7 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -35,10 +35,7 @@ #include "mongo/db/commands.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/stats/counters.h" -#include "mongo/s/cluster_explain.h" #include "mongo/s/query/cluster_find.h" -#include "mongo/s/strategy.h" -#include "mongo/util/timer.h" namespace mongo { namespace { @@ -116,31 +113,13 @@ public: // Parse the command BSON to a LiteParsedQuery. bool isExplain = true; - auto lpqStatus = LiteParsedQuery::makeFromFindCommand(std::move(nss), cmdObj, isExplain); - if (!lpqStatus.isOK()) { - return lpqStatus.getStatus(); + auto lpq = LiteParsedQuery::makeFromFindCommand(std::move(nss), cmdObj, isExplain); + if (!lpq.isOK()) { + return lpq.getStatus(); } - auto& lpq = lpqStatus.getValue(); - - BSONObjBuilder explainCmdBob; - int options = 0; - ClusterExplain::wrapAsExplain( - cmdObj, verbosity, serverSelectionMetadata, &explainCmdBob, &options); - - // We will time how long it takes to run the commands on the shards. - Timer timer; - - vector<Strategy::CommandResult> shardResults; - Strategy::commandOp( - txn, dbname, explainCmdBob.obj(), options, fullns, lpq->getFilter(), &shardResults); - - long long millisElapsed = timer.millis(); - - const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, cmdObj); - - return ClusterExplain::buildExplainResult( - txn, shardResults, mongosStageName, millisElapsed, out); + return ClusterFind::runExplain( + txn, cmdObj, *lpq.getValue(), verbosity, serverSelectionMetadata, out); } bool run(OperationContext* txn, diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index 0d0fb418333..4f40dd3c795 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -42,9 +42,11 @@ #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/find_common.h" #include "mongo/db/query/getmore_request.h" +#include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/s/catalog/catalog_cache.h" #include "mongo/s/chunk_manager.h" #include "mongo/s/client/shard_registry.h" +#include "mongo/s/cluster_explain.h" #include "mongo/s/config.h" #include "mongo/s/grid.h" #include "mongo/s/query/cluster_client_cursor_impl.h" @@ -329,6 +331,37 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* txn, return CursorResponse(request.nss, idToReturn, std::move(batch), startingFrom); } +Status ClusterFind::runExplain(OperationContext* txn, + const BSONObj& findCommand, + const LiteParsedQuery& lpq, + ExplainCommon::Verbosity verbosity, + const rpc::ServerSelectionMetadata& serverSelectionMetadata, + BSONObjBuilder* out) { + BSONObjBuilder explainCmdBob; + int options = 0; + ClusterExplain::wrapAsExplain( + findCommand, verbosity, serverSelectionMetadata, &explainCmdBob, &options); + + // We will time how long it takes to run the commands on the shards. + Timer timer; + + std::vector<Strategy::CommandResult> shardResults; + Strategy::commandOp(txn, + lpq.nss().db().toString(), + explainCmdBob.obj(), + options, + lpq.nss().toString(), + lpq.getFilter(), + &shardResults); + + long long millisElapsed = timer.millis(); + + const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, findCommand); + + return ClusterExplain::buildExplainResult( + txn, shardResults, mongosStageName, millisElapsed, out); +} + StatusWith<ReadPreferenceSetting> ClusterFind::extractUnwrappedReadPref(const BSONObj& cmdObj, const bool isSlaveOk) { BSONElement queryOptionsElt; diff --git a/src/mongo/s/query/cluster_find.h b/src/mongo/s/query/cluster_find.h index ad878a11b37..7a7d3deac69 100644 --- a/src/mongo/s/query/cluster_find.h +++ b/src/mongo/s/query/cluster_find.h @@ -33,6 +33,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/cursor_id.h" #include "mongo/db/query/cursor_response.h" +#include "mongo/db/query/explain_common.h" namespace mongo { @@ -43,6 +44,10 @@ class OperationContext; struct GetMoreRequest; struct ReadPreferenceSetting; +namespace rpc { +class ServerSelectionMetadata; +} // namespace rpc + /** * Methods for running find and getMore operations across a sharded cluster. */ @@ -71,6 +76,21 @@ public: const GetMoreRequest& request); /** + * Helper to run an explain of a find operation on the shards. Fills 'out' with the result of + * the of the explain command on success. On failure, returns a non-OK status and does not + * modify 'out'. + * + * Used both if mongos receives an explain command and if it receives an OP_QUERY find with the + * $explain modifier. + */ + static Status runExplain(OperationContext* txn, + const BSONObj& findCommand, + const LiteParsedQuery& lpq, + ExplainCommon::Verbosity verbosity, + const rpc::ServerSelectionMetadata& serverSelectionMetadata, + BSONObjBuilder* out); + + /** * Extracts the read preference from 'cmdObj', or determines the read pref based on 'isSlaveOk' * if 'cmdObj' does not contain a read preference. * diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp index 89bc8a0e2d4..357cd8843c0 100644 --- a/src/mongo/s/strategy.cpp +++ b/src/mongo/s/strategy.cpp @@ -49,6 +49,7 @@ #include "mongo/db/query/lite_parsed_query.h" #include "mongo/db/query/getmore_request.h" #include "mongo/db/stats/counters.h" +#include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/s/bson_serializable.h" #include "mongo/s/catalog/catalog_cache.h" #include "mongo/s/client/shard_registry.h" @@ -194,6 +195,34 @@ void Strategy::queryOp(OperationContext* txn, Request& request) { auto canonicalQuery = CanonicalQuery::canonicalize(q, WhereCallbackNoop()); uassertStatusOK(canonicalQuery.getStatus()); + // If the $explain flag was set, we must run the operation on the shards as an explain + // command rather than a find command. + if (canonicalQuery.getValue()->getParsed().isExplain()) { + const LiteParsedQuery& lpq = canonicalQuery.getValue()->getParsed(); + BSONObj findCommand = lpq.asFindCommand(); + + // We default to allPlansExecution verbosity. + auto verbosity = ExplainCommon::EXEC_ALL_PLANS; + + const bool secondaryOk = (readPreference.pref != ReadPreference::PrimaryOnly); + rpc::ServerSelectionMetadata metadata(secondaryOk, readPreference); + + BSONObjBuilder explainBuilder; + uassertStatusOK(ClusterFind::runExplain( + txn, findCommand, lpq, verbosity, metadata, &explainBuilder)); + + BSONObj explainObj = explainBuilder.done(); + replyToQuery(0, // query result flags + request.p(), + request.m(), + static_cast<const void*>(explainObj.objdata()), + explainObj.objsize(), + 1, // numResults + 0, // startingFrom + CursorId(0)); + return; + } + // Do the work to generate the first batch of results. This blocks waiting to get responses // from the shard(s). std::vector<BSONObj> batch; @@ -205,11 +234,11 @@ void Strategy::queryOp(OperationContext* txn, Request& request) { ClusterFind::runQuery(txn, *canonicalQuery.getValue(), readPreference, &batch); uassertStatusOK(cursorId.getStatus()); - // Build the response document. // TODO: this constant should be shared between mongos and mongod, and should // not be inside ShardedClientCursor. BufBuilder buffer(ShardedClientCursor::INIT_REPLY_BUFFER_SIZE); + // Fill out the response buffer. int numResults = 0; for (const auto& obj : batch) { buffer.appendBuf((void*)obj.objdata(), obj.objsize()); |