diff options
author | Esha Maharishi <esha.maharishi@mongodb.com> | 2017-04-17 15:51:21 -0400 |
---|---|---|
committer | Esha Maharishi <esha.maharishi@mongodb.com> | 2017-04-19 17:48:50 -0400 |
commit | 4354125dd663c7b6b0ba853a70c98dc786f9385a (patch) | |
tree | 113317e0060907a5bda58a5b47557bc95e65e903 /src/mongo/s | |
parent | 2f7b34fc95a2b101344fd7ab1f51d97ecf02da46 (diff) | |
download | mongo-4354125dd663c7b6b0ba853a70c98dc786f9385a.tar.gz |
SERVER-28726 make ClusterCountCmd::explain, Strategy::explainFind, and DistinctCmd::explain use the ARS
Diffstat (limited to 'src/mongo/s')
-rw-r--r-- | src/mongo/s/commands/cluster_commands_common.cpp | 43 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_commands_common.h | 28 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_count_cmd.cpp | 49 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_current_op.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_db_stats_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_explain.cpp | 62 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_explain.h | 32 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_and_modify_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_repair_database_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_write_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/commands_public.cpp | 63 | ||||
-rw-r--r-- | src/mongo/s/commands/strategy.cpp | 49 | ||||
-rw-r--r-- | src/mongo/s/commands/strategy.h | 5 |
13 files changed, 225 insertions, 119 deletions
diff --git a/src/mongo/s/commands/cluster_commands_common.cpp b/src/mongo/s/commands/cluster_commands_common.cpp index 7f104f3de4e..97d3e7a429e 100644 --- a/src/mongo/s/commands/cluster_commands_common.cpp +++ b/src/mongo/s/commands/cluster_commands_common.cpp @@ -124,14 +124,9 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> gatherResponses( OperationContext* opCtx, const std::string& dbName, const BSONObj& cmdObj, + const ReadPreferenceSetting& readPref, const std::vector<AsyncRequestsSender::Request>& requests, BSONObj* viewDefinition) { - // Extract the readPreference from the command. - const auto queryOptionsObj = cmdObj.getObjectField(QueryRequest::kUnwrappedReadPrefField); - const auto readPrefObj = queryOptionsObj.getObjectField(QueryRequest::kWrappedReadPrefField); - const auto readPref = readPrefObj.isEmpty() - ? ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet()) - : uassertStatusOK(ReadPreferenceSetting::fromBSON(readPrefObj)); // Send the requests. LOG(0) << "Dispatching command " << redact(cmdObj) << " to " << requests.size() @@ -201,7 +196,7 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> gatherResponses( // Either we failed to get a response, or the command had a non-OK status that we can store // as an individual shard response. - LOG(2) << "Got error " << response.swResponse.getStatus() << " from shard " + LOG(2) << "Received error " << response.swResponse.getStatus() << " from shard " << response.shardId; responses.push_back(std::move(response)); } @@ -211,17 +206,34 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> gatherResponses( } // namespace -StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGather(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj) { +ReadPreferenceSetting getReadPref(const BSONObj& cmdObj) { + const auto queryOptionsObj = cmdObj.getObjectField(QueryRequest::kUnwrappedReadPrefField); + const auto readPrefObj = queryOptionsObj.getObjectField(QueryRequest::kWrappedReadPrefField); + return readPrefObj.isEmpty() ? ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet()) + : uassertStatusOK(ReadPreferenceSetting::fromBSON(readPrefObj)); +} + +ReadPreferenceSetting getReadPref(const rpc::ServerSelectionMetadata& ssm) { + return ssm.getReadPreference() + ? *ssm.getReadPreference() + : (ssm.isSecondaryOk() ? ReadPreferenceSetting(ReadPreference::SecondaryPreferred, TagSet()) + : ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet())); +} + +StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGather( + OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + const ReadPreferenceSetting& readPref) { auto requests = buildRequestsForAllShards(opCtx, cmdObj); - return gatherResponses(opCtx, dbName, cmdObj, requests, nullptr /* viewDefinition */); + return gatherResponses(opCtx, dbName, cmdObj, readPref, requests, nullptr /* viewDefinition */); } StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGatherForNamespace( OperationContext* opCtx, const NamespaceString& nss, const BSONObj& cmdObj, + const ReadPreferenceSetting& readPref, const boost::optional<BSONObj> query, const boost::optional<BSONObj> collation, const bool appendShardVersion, @@ -243,15 +255,18 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGatherForNamespace opCtx, routingInfo, cmdObj, query, collation, appendShardVersion); // Retrieve the responses from the shards. - swResponses = gatherResponses(opCtx, nss.db().toString(), cmdObj, requests, viewDefinition); + swResponses = + gatherResponses(opCtx, nss.db().toString(), cmdObj, readPref, requests, viewDefinition); + ++numAttempts; // If any shard returned a stale shardVersion error, invalidate the routing table cache. // This will cause the cache to be refreshed the next time it is accessed. if (ErrorCodes::isStaleShardingError(swResponses.getStatus().code())) { Grid::get(opCtx)->catalogCache()->onStaleConfigError(std::move(routingInfo)); + LOG(1) << "got stale shardVersion error " << swResponses.getStatus() + << " while dispatching " << redact(cmdObj) << " after " << numAttempts + << " dispatch attempts"; } - - ++numAttempts; } while (numAttempts < kMaxNumStaleVersionRetries && !swResponses.getStatus().isOK()); return swResponses; } diff --git a/src/mongo/s/commands/cluster_commands_common.h b/src/mongo/s/commands/cluster_commands_common.h index 5537d72b51b..2572e136eee 100644 --- a/src/mongo/s/commands/cluster_commands_common.h +++ b/src/mongo/s/commands/cluster_commands_common.h @@ -46,15 +46,36 @@ class CachedDatabaseInfo; class OperationContext; /** + * Returns the read preference from the $queryOptions.$readPreference field in the cmdObj if set or + * defaults to PrimaryOnly and an empty TagSet. + */ +ReadPreferenceSetting getReadPref(const BSONObj& cmdObj); + +/** + * Returns the read preference from the ServerSelectionMetadata if set or defaults to PrimaryOnly + * and an empty TagSet. + * + * This is used by explain commands, where the read preference is extracted and placed into + * ServerSelectionMetadata before the explain command is run. + * + * This is because only the value of the 'explain' field in the cmdObj is passed to the Command's + * explain() method, and the readPreference is at the same level as the 'explain' field: + * { explain: { find: "foo" }, $queryOptions: { $readPreference: { ... } } } + */ +ReadPreferenceSetting getReadPref(const rpc::ServerSelectionMetadata& ssm); + +/** * Broadcasts 'cmdObj' to all shards and returns the responses as a vector. * * Returns a non-OK status if a failure occurs on *this* node during execution. * Otherwise, returns success and a list of responses from shards (including errors from the shards * or errors reaching the shards). */ -StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGather(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj); +StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGather( + OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + const ReadPreferenceSetting& readPref); /** * Uses the routing table cache to broadcast a command on a namespace. By default, attaches @@ -79,6 +100,7 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> scatterGatherForNamespace OperationContext* opCtx, const NamespaceString& nss, const BSONObj& cmdObj, + const ReadPreferenceSetting& readPref, const boost::optional<BSONObj> query, const boost::optional<BSONObj> collation, const bool appendShardVersion = true, diff --git a/src/mongo/s/commands/cluster_count_cmd.cpp b/src/mongo/s/commands/cluster_count_cmd.cpp index 74a4933c857..d100c4c6f91 100644 --- a/src/mongo/s/commands/cluster_count_cmd.cpp +++ b/src/mongo/s/commands/cluster_count_cmd.cpp @@ -36,6 +36,7 @@ #include "mongo/db/query/view_response_formatter.h" #include "mongo/db/views/resolved_view.h" #include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/s/catalog_cache.h" #include "mongo/s/commands/cluster_aggregate.h" #include "mongo/s/commands/cluster_commands_common.h" @@ -144,9 +145,10 @@ public: auto swShardResponses = scatterGatherForNamespace(opCtx, nss, countCmdObj, + getReadPref(countCmdObj), filter, collation, - true /* do shard versioning */, + true, // do shard versioning &viewDefinition); if (ErrorCodes::CommandOnShardedViewNotSupportedOnMongod == swShardResponses.getStatus()) { @@ -239,7 +241,7 @@ public: const std::string& dbname, const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, - const rpc::ServerSelectionMetadata& serverSelectionMetadata, + const rpc::ServerSelectionMetadata& ssm, BSONObjBuilder* out) const override { const NamespaceString nss(parseNs(dbname, cmdObj)); uassert(ErrorCodes::InvalidNamespace, @@ -264,26 +266,29 @@ public: } BSONObjBuilder explainCmdBob; - int options = 0; - ClusterExplain::wrapAsExplain( - cmdObj, verbosity, serverSelectionMetadata, &explainCmdBob, &options); + ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); // We will time how long it takes to run the commands on the shards Timer timer; - std::vector<Strategy::CommandResult> shardResults; - Strategy::commandOp(opCtx, - dbname, - explainCmdBob.obj(), - nss.ns(), - targetingQuery, - targetingCollation, - &shardResults); + BSONObj viewDefinition; + auto swShardResponses = scatterGatherForNamespace(opCtx, + nss, + explainCmdBob.obj(), + getReadPref(ssm), + targetingQuery, + targetingCollation, + true, // do shard versioning + &viewDefinition); long long millisElapsed = timer.millis(); - if (shardResults.size() == 1 && - ResolvedView::isResolvedViewErrorResponse(shardResults[0].result)) { + if (ErrorCodes::CommandOnShardedViewNotSupportedOnMongod == swShardResponses.getStatus()) { + uassert(ErrorCodes::InternalError, + str::stream() << "Missing resolved view definition, but remote returned " + << ErrorCodes::errorString(swShardResponses.getStatus().code()), + !viewDefinition.isEmpty()); + auto countRequest = CountRequest::parseFromBSON(dbname, cmdObj, true); if (!countRequest.isOK()) { return countRequest.getStatus(); @@ -300,7 +305,7 @@ public: return aggRequestOnView.getStatus(); } - auto resolvedView = ResolvedView::fromBSON(shardResults[0].result); + auto resolvedView = ResolvedView::fromBSON(viewDefinition); auto resolvedAggRequest = resolvedView.asExpandedViewAggregation(aggRequestOnView.getValue()); auto resolvedAggCmd = resolvedAggRequest.serializeToCommandObj().toBson(); @@ -313,10 +318,18 @@ public: opCtx, nsStruct, resolvedAggRequest, resolvedAggCmd, out); } - const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, cmdObj); + uassertStatusOK(swShardResponses.getStatus()); + auto shardResponses = std::move(swShardResponses.getValue()); + + const char* mongosStageName = + ClusterExplain::getStageNameForReadOp(shardResponses.size(), cmdObj); return ClusterExplain::buildExplainResult( - opCtx, shardResults, mongosStageName, millisElapsed, out); + opCtx, + ClusterExplain::downconvert(opCtx, shardResponses), + mongosStageName, + millisElapsed, + out); } private: diff --git a/src/mongo/s/commands/cluster_current_op.cpp b/src/mongo/s/commands/cluster_current_op.cpp index d509370b06b..009fb1d9ae2 100644 --- a/src/mongo/s/commands/cluster_current_op.cpp +++ b/src/mongo/s/commands/cluster_current_op.cpp @@ -85,7 +85,8 @@ public: BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - auto shardResponses = uassertStatusOK(scatterGather(opCtx, dbName, cmdObj)); + auto shardResponses = + uassertStatusOK(scatterGather(opCtx, dbName, cmdObj, getReadPref(cmdObj))); if (!appendRawResponses(opCtx, &errmsg, &output, shardResponses)) { return false; } diff --git a/src/mongo/s/commands/cluster_db_stats_cmd.cpp b/src/mongo/s/commands/cluster_db_stats_cmd.cpp index 8bddb22148b..3317fdd07ce 100644 --- a/src/mongo/s/commands/cluster_db_stats_cmd.cpp +++ b/src/mongo/s/commands/cluster_db_stats_cmd.cpp @@ -68,7 +68,8 @@ public: BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - auto shardResponses = uassertStatusOK(scatterGather(opCtx, dbName, cmdObj)); + auto shardResponses = + uassertStatusOK(scatterGather(opCtx, dbName, cmdObj, getReadPref(cmdObj))); if (!appendRawResponses(opCtx, &errmsg, &output, shardResponses)) { return false; } diff --git a/src/mongo/s/commands/cluster_explain.cpp b/src/mongo/s/commands/cluster_explain.cpp index e15a9939976..3add2b0e580 100644 --- a/src/mongo/s/commands/cluster_explain.cpp +++ b/src/mongo/s/commands/cluster_explain.cpp @@ -29,6 +29,8 @@ #include "mongo/platform/basic.h" #include "mongo/bson/bsonmisc.h" +#include "mongo/db/commands.h" +#include "mongo/rpc/get_status_from_command_result.h" #include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/commands/cluster_explain.h" @@ -100,33 +102,55 @@ bool appendElementsIfRoom(BSONObjBuilder* bob, const BSONObj& toAppend) { } // namespace // static -void ClusterExplain::wrapAsExplainForOP_COMMAND(const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - BSONObjBuilder* explainBuilder) { - explainBuilder->append("explain", cmdObj); - explainBuilder->append("verbosity", ExplainOptions::verbosityString(verbosity)); - - // Propagate readConcern - if (auto readConcern = cmdObj["readConcern"]) { - explainBuilder->append(readConcern); +std::vector<Strategy::CommandResult> ClusterExplain::downconvert( + OperationContext* opCtx, const std::vector<AsyncRequestsSender::Response>& responses) { + std::vector<Strategy::CommandResult> results; + for (auto& response : responses) { + Status status = Status::OK(); + if (response.swResponse.isOK()) { + auto& result = response.swResponse.getValue().data; + status = getStatusFromCommandResult(result); + if (status.isOK()) { + invariant(response.shardHostAndPort); + results.emplace_back( + response.shardId, ConnectionString(*response.shardHostAndPort), result); + continue; + } + } + // Convert the error status back into the format of a command result. + BSONObjBuilder statusObjBob; + Command::appendCommandStatus(statusObjBob, status); + + // Get the Shard object in order to get the ConnectionString. + auto shard = + uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, response.shardId)); + results.emplace_back(response.shardId, shard->getConnString(), statusObjBob.obj()); } + return results; } // static void ClusterExplain::wrapAsExplain(const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, - const rpc::ServerSelectionMetadata& serverSelectionMetadata, - BSONObjBuilder* out, - int* optionsOut) { - BSONObjBuilder explainBuilder; - explainBuilder.append("explain", cmdObj); - explainBuilder.append("verbosity", ExplainOptions::verbosityString(verbosity)); + BSONObjBuilder* explainBuilder) { + explainBuilder->append("explain", cmdObj); + explainBuilder->append("verbosity", ExplainOptions::verbosityString(verbosity)); // Propagate readConcern if (auto readConcern = cmdObj["readConcern"]) { - explainBuilder.append(readConcern); + explainBuilder->append(readConcern); } +} +// static +void ClusterExplain::wrapAsExplainDeprecated( + const BSONObj& cmdObj, + ExplainOptions::Verbosity verbosity, + const rpc::ServerSelectionMetadata& serverSelectionMetadata, + BSONObjBuilder* out, + int* optionsOut) { + BSONObjBuilder explainBuilder; + wrapAsExplain(cmdObj, verbosity, &explainBuilder); const BSONObj explainCmdObj = explainBuilder.done(); // Attach metadata to the explain command in legacy format. @@ -202,9 +226,8 @@ Status ClusterExplain::validateShardResults(const vector<Strategy::CommandResult } // static -const char* ClusterExplain::getStageNameForReadOp( - const vector<Strategy::CommandResult>& shardResults, const BSONObj& explainObj) { - if (shardResults.size() == 1) { +const char* ClusterExplain::getStageNameForReadOp(size_t numShards, const BSONObj& explainObj) { + if (numShards == 1) { return kSingleShard; } else if (explainObj.hasField("sort")) { return kMergeSortFromShards; @@ -373,4 +396,5 @@ Status ClusterExplain::buildExplainResult(OperationContext* opCtx, return Status::OK(); } + } // namespace mongo diff --git a/src/mongo/s/commands/cluster_explain.h b/src/mongo/s/commands/cluster_explain.h index e2e3b8cc5ba..1bc72aacd6e 100644 --- a/src/mongo/s/commands/cluster_explain.h +++ b/src/mongo/s/commands/cluster_explain.h @@ -31,6 +31,7 @@ #include <string> #include "mongo/db/query/explain_options.h" +#include "mongo/s/async_requests_sender.h" #include "mongo/s/commands/strategy.h" #include "mongo/s/write_ops/batched_command_request.h" @@ -49,6 +50,17 @@ class ServerSelectionMetadata; class ClusterExplain { public: /** + * Temporary crutch to allow a single implementation of the methods in this file. Since + * AsyncRequestsSender::Response is a strict superset of Strategy::CommandResult, we leave the + * implementations in terms of Strategy::CommandResult and convert down. + * + * TODO(esha): remove once Strategy::commandOp is removed, and make these methods take + * vector<AsyncRequestsSender::Response>. + */ + static std::vector<Strategy::CommandResult> downconvert( + OperationContext* opCtx, const std::vector<AsyncRequestsSender::Response>& responses); + + /** * Given the BSON specification for a command, 'cmdObj', wraps the object in order to produce * the BSON for an explain of that command, at the given verbosity level 'verbosity.' * @@ -57,9 +69,9 @@ public: * Unlike wrapAsExplain, does not downconvert the command to OP_QUERY. Should be used for paths * that send the command over the NetworkInterfaceASIO rather than DBClient. */ - static void wrapAsExplainForOP_COMMAND(const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - BSONObjBuilder* explainBuilder); + static void wrapAsExplain(const BSONObj& cmdObj, + ExplainOptions::Verbosity verbosity, + BSONObjBuilder* explainBuilder); /** * Given the BSON specification for a command, 'cmdObj', wraps the object in order to @@ -71,19 +83,18 @@ public: * Also uses 'serverSelectionMetdata' to set 'optionsOut' to the options bit vector that should * be forwarded to the shards. */ - static void wrapAsExplain(const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - const rpc::ServerSelectionMetadata& serverSelectionMetadata, - BSONObjBuilder* out, - int* optionsOut); + static void wrapAsExplainDeprecated(const BSONObj& cmdObj, + ExplainOptions::Verbosity verbosity, + const rpc::ServerSelectionMetadata& serverSelectionMetadata, + BSONObjBuilder* out, + int* optionsOut); /** * Determines the kind of "execution stage" that mongos would use in order to collect * the results from the shards, assuming that the command being explained is a read * operation such as find or count. */ - static const char* getStageNameForReadOp( - const std::vector<Strategy::CommandResult>& shardResults, const BSONObj& explainObj); + static const char* getStageNameForReadOp(size_t numShards, const BSONObj& explainObj); /** * Command implementations on mongos use this method to construct the sharded explain @@ -97,6 +108,7 @@ public: long long millisElapsed, BSONObjBuilder* out); + // // Names of mock mongos execution stages. // diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index c586d0ad6af..dd0f5292fb2 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -129,7 +129,7 @@ public: BSONObjBuilder explainCmd; int options = 0; - ClusterExplain::wrapAsExplain( + ClusterExplain::wrapAsExplainDeprecated( cmdObj, verbosity, serverSelectionMetadata, &explainCmd, &options); // Time how long it takes to run the explain command on the shard. diff --git a/src/mongo/s/commands/cluster_repair_database_cmd.cpp b/src/mongo/s/commands/cluster_repair_database_cmd.cpp index adfb35d67ab..bd3d11314eb 100644 --- a/src/mongo/s/commands/cluster_repair_database_cmd.cpp +++ b/src/mongo/s/commands/cluster_repair_database_cmd.cpp @@ -64,7 +64,8 @@ public: BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - auto shardResponses = uassertStatusOK(scatterGather(opCtx, dbName, cmdObj)); + auto shardResponses = + uassertStatusOK(scatterGather(opCtx, dbName, cmdObj, getReadPref(cmdObj))); return appendRawResponses(opCtx, &errmsg, &output, std::move(shardResponses)); } diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index d39adbd5e49..2a68ad03402 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -111,7 +111,7 @@ public: } BSONObjBuilder explainCmdBob; - ClusterExplain::wrapAsExplainForOP_COMMAND(cmdObj, verbosity, &explainCmdBob); + ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); // We will time how long it takes to run the commands on the shards. Timer timer; diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp index 745422ebf99..205311cd4b3 100644 --- a/src/mongo/s/commands/commands_public.cpp +++ b/src/mongo/s/commands/commands_public.cpp @@ -225,6 +225,7 @@ protected: auto shardResponses = uassertStatusOK(scatterGatherForNamespace(opCtx, nss, cmdObj, + getReadPref(cmdObj), boost::none, // filter boost::none, // collation _appendShardVersion)); @@ -897,7 +898,7 @@ public: { BSONObjBuilder explainCmdBob; - ClusterExplain::wrapAsExplain( + ClusterExplain::wrapAsExplainDeprecated( cmdObj, verbosity, serverSelectionMetadata, &explainCmdBob, &options); command = explainCmdBob.obj(); } @@ -1125,7 +1126,7 @@ public: const std::string& dbname, const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, - const rpc::ServerSelectionMetadata& serverSelectionMetadata, + const rpc::ServerSelectionMetadata& ssm, BSONObjBuilder* out) const { const NamespaceString nss(parseNsCollectionRequired(dbname, cmdObj)); @@ -1146,33 +1147,33 @@ public: } // Extract the targeting collation. - auto targetingCollation = getCollation(cmdObj); - if (!targetingCollation.isOK()) { - return targetingCollation.getStatus(); - } + auto targetingCollation = uassertStatusOK(getCollation(cmdObj)); BSONObjBuilder explainCmdBob; - int options = 0; - ClusterExplain::wrapAsExplain( - cmdObj, verbosity, serverSelectionMetadata, &explainCmdBob, &options); + ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); // We will time how long it takes to run the commands on the shards. Timer timer; - vector<Strategy::CommandResult> shardResults; - Strategy::commandOp(opCtx, - dbname, - explainCmdBob.obj(), - nss.ns(), - targetingQuery, - targetingCollation.getValue(), - &shardResults); + BSONObj viewDefinition; + auto swShardResponses = scatterGatherForNamespace(opCtx, + nss, + explainCmdBob.obj(), + getReadPref(ssm), + targetingQuery, + targetingCollation, + true, // do shard versioning + &viewDefinition); long long millisElapsed = timer.millis(); - if (shardResults.size() == 1 && - ResolvedView::isResolvedViewErrorResponse(shardResults[0].result)) { - auto resolvedView = ResolvedView::fromBSON(shardResults[0].result); + if (ErrorCodes::CommandOnShardedViewNotSupportedOnMongod == swShardResponses.getStatus()) { + uassert(ErrorCodes::InternalError, + str::stream() << "Missing resolved view definition, but remote returned " + << ErrorCodes::errorString(swShardResponses.getStatus().code()), + !viewDefinition.isEmpty()); + + auto resolvedView = ResolvedView::fromBSON(viewDefinition); auto parsedDistinct = ParsedDistinct::parse( opCtx, resolvedView.getNamespace(), cmdObj, ExtensionsCallbackNoop(), true); if (!parsedDistinct.isOK()) { @@ -1202,10 +1203,18 @@ public: opCtx, nsStruct, resolvedAggRequest, resolvedAggCmd, out); } - const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, cmdObj); + uassertStatusOK(swShardResponses.getStatus()); + auto shardResponses = std::move(swShardResponses.getValue()); + + const char* mongosStageName = + ClusterExplain::getStageNameForReadOp(shardResponses.size(), cmdObj); return ClusterExplain::buildExplainResult( - opCtx, shardResults, mongosStageName, millisElapsed, out); + opCtx, + ClusterExplain::downconvert(opCtx, shardResponses), + mongosStageName, + millisElapsed, + out); } } disinctCmd; @@ -1422,20 +1431,12 @@ public: shardArray.append(shardId.toString()); } - // Extract the readPreference from the command. - const auto queryOptionsObj = cmdObj.getObjectField(QueryRequest::kUnwrappedReadPrefField); - const auto readPrefObj = - queryOptionsObj.getObjectField(QueryRequest::kWrappedReadPrefField); - const auto readPref = readPrefObj.isEmpty() - ? ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet()) - : uassertStatusOK(ReadPreferenceSetting::fromBSON(readPrefObj)); - // Send the requests. AsyncRequestsSender ars(opCtx, Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(), dbName, requests, - readPref); + getReadPref(cmdObj)); // Receive the responses. multimap<double, BSONObj> results; // TODO: maybe use merge-sort instead diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 9eb37618c82..66386fd5767 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -60,6 +60,7 @@ #include "mongo/s/client/parallel.h" #include "mongo/s/client/shard_connection.h" #include "mongo/s/client/shard_registry.h" +#include "mongo/s/commands/cluster_commands_common.h" #include "mongo/s/commands/cluster_explain.h" #include "mongo/s/grid.h" #include "mongo/s/query/cluster_cursor_manager.h" @@ -636,37 +637,47 @@ Status Strategy::explainFind(OperationContext* opCtx, const BSONObj& findCommand, const QueryRequest& qr, ExplainOptions::Verbosity verbosity, - const rpc::ServerSelectionMetadata& serverSelectionMetadata, + const rpc::ServerSelectionMetadata& ssm, BSONObjBuilder* out) { BSONObjBuilder explainCmdBob; - int options = 0; - ClusterExplain::wrapAsExplain( - findCommand, verbosity, serverSelectionMetadata, &explainCmdBob, &options); + ClusterExplain::wrapAsExplain(findCommand, verbosity, &explainCmdBob); // We will time how long it takes to run the commands on the shards. Timer timer; - std::vector<Strategy::CommandResult> shardResults; - Strategy::commandOp(opCtx, - qr.nss().db().toString(), - explainCmdBob.obj(), - qr.nss().toString(), - qr.getFilter(), - qr.getCollation(), - &shardResults); + BSONObj viewDefinition; + auto swShardResponses = scatterGatherForNamespace(opCtx, + qr.nss(), + explainCmdBob.obj(), + getReadPref(ssm), + qr.getFilter(), + qr.getCollation(), + true, // do shard versioning + &viewDefinition); long long millisElapsed = timer.millis(); - if (shardResults.size() == 1 && - ResolvedView::isResolvedViewErrorResponse(shardResults[0].result)) { - out->append("resolvedView", shardResults[0].result.getObjectField("resolvedView")); - return getStatusFromCommandResult(shardResults[0].result); + if (ErrorCodes::CommandOnShardedViewNotSupportedOnMongod == swShardResponses.getStatus()) { + uassert(ErrorCodes::InternalError, + str::stream() << "Missing resolved view definition, but remote returned " + << ErrorCodes::errorString(swShardResponses.getStatus().code()), + !viewDefinition.isEmpty()); + + out->appendElements(viewDefinition); + return swShardResponses.getStatus(); } - const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, findCommand); + uassertStatusOK(swShardResponses.getStatus()); + auto shardResponses = std::move(swShardResponses.getValue()); + + const char* mongosStageName = + ClusterExplain::getStageNameForReadOp(shardResponses.size(), findCommand); - return ClusterExplain::buildExplainResult( - opCtx, shardResults, mongosStageName, millisElapsed, out); + return ClusterExplain::buildExplainResult(opCtx, + ClusterExplain::downconvert(opCtx, shardResponses), + mongosStageName, + millisElapsed, + out); } /** diff --git a/src/mongo/s/commands/strategy.h b/src/mongo/s/commands/strategy.h index c41fbef75b2..03a1ab0077b 100644 --- a/src/mongo/s/commands/strategy.h +++ b/src/mongo/s/commands/strategy.h @@ -104,6 +104,11 @@ public: BSONObjBuilder* out); struct CommandResult { + CommandResult() = default; + CommandResult(ShardId shardId, ConnectionString target, BSONObj result) + : shardTargetId(std::move(shardId)), + target(std::move(target)), + result(std::move(result)) {} ShardId shardTargetId; ConnectionString target; BSONObj result; |