summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEsha Maharishi <esha.maharishi@mongodb.com>2017-04-17 15:51:21 -0400
committerEsha Maharishi <esha.maharishi@mongodb.com>2017-04-19 17:48:50 -0400
commit4354125dd663c7b6b0ba853a70c98dc786f9385a (patch)
tree113317e0060907a5bda58a5b47557bc95e65e903
parent2f7b34fc95a2b101344fd7ab1f51d97ecf02da46 (diff)
downloadmongo-4354125dd663c7b6b0ba853a70c98dc786f9385a.tar.gz
SERVER-28726 make ClusterCountCmd::explain, Strategy::explainFind, and DistinctCmd::explain use the ARS
-rw-r--r--src/mongo/db/commands/explain_cmd.cpp15
-rw-r--r--src/mongo/s/commands/cluster_commands_common.cpp43
-rw-r--r--src/mongo/s/commands/cluster_commands_common.h28
-rw-r--r--src/mongo/s/commands/cluster_count_cmd.cpp49
-rw-r--r--src/mongo/s/commands/cluster_current_op.cpp3
-rw-r--r--src/mongo/s/commands/cluster_db_stats_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_explain.cpp62
-rw-r--r--src/mongo/s/commands/cluster_explain.h32
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_repair_database_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_write_cmd.cpp2
-rw-r--r--src/mongo/s/commands/commands_public.cpp63
-rw-r--r--src/mongo/s/commands/strategy.cpp49
-rw-r--r--src/mongo/s/commands/strategy.h5
14 files changed, 239 insertions, 120 deletions
diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp
index 948cd8dd530..9f49c8b38e7 100644
--- a/src/mongo/db/commands/explain_cmd.cpp
+++ b/src/mongo/db/commands/explain_cmd.cpp
@@ -56,7 +56,6 @@ class CmdExplain : public Command {
public:
CmdExplain() : Command("explain") {}
-
virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
return false;
}
@@ -84,6 +83,20 @@ public:
help << "explain database reads and writes";
}
+ std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override {
+ uassert(ErrorCodes::BadValue,
+ "explain command requires a nested object",
+ Object == cmdObj.firstElement().type());
+ auto explainObj = cmdObj.firstElement().Obj();
+
+ Command* commToExplain = Command::findCommand(explainObj.firstElementFieldName());
+ uassert(ErrorCodes::CommandNotFound,
+ str::stream() << "explain failed due to unknown command: "
+ << explainObj.firstElementFieldName(),
+ commToExplain);
+ return commToExplain->parseNs(dbname, explainObj);
+ }
+
/**
* You are authorized to run an explain if you are authorized to run
* the command that you are explaining. The auth check is performed recursively
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;