diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-02-27 15:56:37 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-03-05 18:15:00 -0500 |
commit | 763f5905c2c8cc9ce67387434f7343b3250f3e9d (patch) | |
tree | e78a7e02380f3e1a20a6ff1151d040da459fdc53 /src/mongo | |
parent | c207a0ced18bba58a8ad1b08df85b1e0a0b136f9 (diff) | |
download | mongo-763f5905c2c8cc9ce67387434f7343b3250f3e9d.tar.gz |
SERVER-27664 Use scatterGatherVersionedTargetByRoutingTable instead of passthrough in commands_public.cpp
This change replaces all usages of passthrough, which are used for
sharded and unsharded collection routing from commands_public.cpp. All
remaining usages of passthrough will be replaced with direct
Shard::runCommand instead.
Diffstat (limited to 'src/mongo')
20 files changed, 393 insertions, 315 deletions
diff --git a/src/mongo/db/sessions_collection_config_server.cpp b/src/mongo/db/sessions_collection_config_server.cpp index 8a4f97cdca9..179687e33d4 100644 --- a/src/mongo/db/sessions_collection_config_server.cpp +++ b/src/mongo/db/sessions_collection_config_server.cpp @@ -80,7 +80,6 @@ Status SessionsCollectionConfigServer::_shardCollectionIfNeeded(OperationContext Status SessionsCollectionConfigServer::_generateIndexesIfNeeded(OperationContext* opCtx) { try { scatterGatherOnlyVersionIfUnsharded(opCtx, - SessionsCollection::kSessionsDb.toString(), NamespaceString(SessionsCollection::kSessionsFullNS), SessionsCollection::generateCreateIndexesCmd(), ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/async_requests_sender.cpp b/src/mongo/s/async_requests_sender.cpp index 8cdb7190050..69f61bf989b 100644 --- a/src/mongo/s/async_requests_sender.cpp +++ b/src/mongo/s/async_requests_sender.cpp @@ -52,13 +52,13 @@ const int kMaxNumFailedHostRetryAttempts = 3; AsyncRequestsSender::AsyncRequestsSender(OperationContext* opCtx, executor::TaskExecutor* executor, - const std::string db, + StringData dbName, const std::vector<AsyncRequestsSender::Request>& requests, const ReadPreferenceSetting& readPreference, Shard::RetryPolicy retryPolicy) : _opCtx(opCtx), _executor(executor), - _db(std::move(db)), + _db(dbName.toString()), _readPreference(readPreference), _retryPolicy(retryPolicy) { for (const auto& request : requests) { diff --git a/src/mongo/s/async_requests_sender.h b/src/mongo/s/async_requests_sender.h index 70d574a8ef7..bafeed53555 100644 --- a/src/mongo/s/async_requests_sender.h +++ b/src/mongo/s/async_requests_sender.h @@ -124,7 +124,7 @@ public: */ AsyncRequestsSender(OperationContext* opCtx, executor::TaskExecutor* executor, - const std::string db, + StringData dbName, const std::vector<AsyncRequestsSender::Request>& requests, const ReadPreferenceSetting& readPreference, Shard::RetryPolicy retryPolicy); diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 11765392956..9dc7ae2124a 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -28,6 +28,7 @@ env.Library( 'cluster_add_shard_to_zone_cmd.cpp', 'cluster_aggregate.cpp', 'cluster_available_query_options_cmd.cpp', + 'cluster_coll_stats_cmd.cpp', 'cluster_collection_mod_cmd.cpp', 'cluster_compact_cmd.cpp', 'cluster_control_balancer_cmd.cpp', @@ -35,6 +36,7 @@ env.Library( 'cluster_create_cmd.cpp', 'cluster_create_indexes_cmd.cpp', 'cluster_current_op.cpp', + 'cluster_data_size_cmd.cpp', 'cluster_db_stats_cmd.cpp', 'cluster_distinct_cmd.cpp', 'cluster_drop_cmd.cpp', diff --git a/src/mongo/s/commands/cluster_aggregate.cpp b/src/mongo/s/commands/cluster_aggregate.cpp index 6c3f604bdd2..2550179e3de 100644 --- a/src/mongo/s/commands/cluster_aggregate.cpp +++ b/src/mongo/s/commands/cluster_aggregate.cpp @@ -443,8 +443,7 @@ DispatchShardPipelineResults dispatchShardPipeline( // should not participate in the shard version protocol. shardResults = scatterGatherUnversionedTargetAllShards(opCtx, - executionNss.db().toString(), - executionNss, + executionNss.db(), targetedCommand, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent); @@ -453,8 +452,8 @@ DispatchShardPipelineResults dispatchShardPipeline( // shards, and should participate in the shard version protocol. shardResults = scatterGatherVersionedTargetByRoutingTable( opCtx, - executionNss.db().toString(), executionNss, + executionNsRoutingInfo, targetedCommand, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, diff --git a/src/mongo/s/commands/cluster_coll_stats_cmd.cpp b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp new file mode 100644 index 00000000000..875a577b9ce --- /dev/null +++ b/src/mongo/s/commands/cluster_coll_stats_cmd.cpp @@ -0,0 +1,211 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/s/commands/cluster_commands_helpers.h" +#include "mongo/s/grid.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace { + +class CollectionStats : public BasicCommand { +public: + CollectionStats() : BasicCommand("collStats", "collstats") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + bool adminOnly() const override { + return false; + } + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const override { + ActionSet actions; + actions.addAction(ActionType::collStats); + out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + const NamespaceString nss(parseNs(dbName, cmdObj)); + + auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); + if (routingInfo.cm()) { + result.appendBool("sharded", true); + } else { + result.appendBool("sharded", false); + result.append("primary", routingInfo.primaryId().toString()); + } + + auto shardResults = scatterGatherVersionedTargetByRoutingTable( + opCtx, + nss, + routingInfo, + CommandHelpers::filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx), + Shard::RetryPolicy::kIdempotent, + {}, + {}); + + BSONObjBuilder shardStats; + std::map<std::string, long long> counts; + std::map<std::string, long long> indexSizes; + + long long maxSize = 0; + long long unscaledCollSize = 0; + + int nindexes = 0; + bool warnedAboutIndexes = false; + + for (const auto& shardResult : shardResults) { + const auto& shardId = shardResult.shardId; + const auto shardResponse = uassertStatusOK(std::move(shardResult.swResponse)); + uassertStatusOK(shardResponse.status); + + const auto& res = shardResponse.data; + uassertStatusOK(getStatusFromCommandResult(res)); + + // We don't know the order that we will encounter the count and size, so we save them + // until we've iterated through all the fields before updating unscaledCollSize + const auto shardObjCount = static_cast<long long>(res["count"].Number()); + + for (const auto& e : res) { + if (str::equals(e.fieldName(), "ns") || // + str::equals(e.fieldName(), "ok") || // + str::equals(e.fieldName(), "lastExtentSize") || // + str::equals(e.fieldName(), "paddingFactor")) { + // Ignored fields + continue; + } else if (str::equals(e.fieldName(), "userFlags") || // + str::equals(e.fieldName(), "capped") || // + str::equals(e.fieldName(), "max") || // + str::equals(e.fieldName(), "paddingFactorNote") || // + str::equals(e.fieldName(), "indexDetails") || // + str::equals(e.fieldName(), "wiredTiger")) { + // Fields that are copied from the first shard only, because they need to match + // across shards + if (!result.hasField(e.fieldName())) + result.append(e); + } else if (str::equals(e.fieldName(), "count") || // + str::equals(e.fieldName(), "size") || // + str::equals(e.fieldName(), "storageSize") || // + str::equals(e.fieldName(), "numExtents") || // + str::equals(e.fieldName(), "totalIndexSize")) { + counts[e.fieldName()] += e.numberLong(); + } else if (str::equals(e.fieldName(), "avgObjSize")) { + const auto shardAvgObjSize = e.numberLong(); + unscaledCollSize += shardAvgObjSize * shardObjCount; + } else if (str::equals(e.fieldName(), "maxSize")) { + const auto shardMaxSize = e.numberLong(); + maxSize = std::max(maxSize, shardMaxSize); + } else if (str::equals(e.fieldName(), "indexSizes")) { + BSONObjIterator k(e.Obj()); + while (k.more()) { + BSONElement temp = k.next(); + indexSizes[temp.fieldName()] += temp.numberLong(); + } + } else if (str::equals(e.fieldName(), "nindexes")) { + int myIndexes = e.numberInt(); + + if (nindexes == 0) { + nindexes = myIndexes; + } else if (nindexes == myIndexes) { + // no-op + } else { + // hopefully this means we're building an index + + if (myIndexes > nindexes) + nindexes = myIndexes; + + if (!warnedAboutIndexes) { + result.append("warning", + "indexes don't all match - ok if ensureIndex is running"); + warnedAboutIndexes = true; + } + } + } else { + log() << "mongos collstats doesn't know about: " << e.fieldName(); + } + } + + shardStats.append(shardId.toString(), res); + } + + result.append("ns", nss.ns()); + + for (const auto& countEntry : counts) { + result.appendNumber(countEntry.first, countEntry.second); + } + + { + BSONObjBuilder ib(result.subobjStart("indexSizes")); + for (const auto& entry : indexSizes) { + ib.appendNumber(entry.first, entry.second); + } + ib.done(); + } + + // The unscaled avgObjSize for each shard is used to get the unscaledCollSize because the + // raw size returned by the shard is affected by the command's scale parameter + if (counts["count"] > 0) + result.append("avgObjSize", (double)unscaledCollSize / (double)counts["count"]); + else + result.append("avgObjSize", 0.0); + + result.append("maxSize", maxSize); + result.append("nindexes", nindexes); + result.append("nchunks", (routingInfo.cm() ? routingInfo.cm()->numChunks() : 1)); + result.append("shards", shardStats.obj()); + + return true; + } + +} collectionStatsCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp index ebb5d0fd788..27823d3ed8d 100644 --- a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp +++ b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp @@ -71,7 +71,6 @@ public: auto shardResponses = scatterGatherOnlyVersionIfUnsharded( opCtx, - dbName, nss, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/commands/cluster_commands_helpers.cpp b/src/mongo/s/commands/cluster_commands_helpers.cpp index ab058a2661d..ec4d2b5e3fe 100644 --- a/src/mongo/s/commands/cluster_commands_helpers.cpp +++ b/src/mongo/s/commands/cluster_commands_helpers.cpp @@ -129,7 +129,7 @@ std::vector<AsyncRequestsSender::Request> buildVersionedRequestsForTargetedShard */ std::vector<AsyncRequestsSender::Response> gatherResponses( OperationContext* opCtx, - const std::string& dbName, + StringData dbName, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy, const std::vector<AsyncRequestsSender::Request>& requests) { @@ -190,50 +190,35 @@ BSONObj appendShardVersion(BSONObj cmdObj, ChunkVersion version) { std::vector<AsyncRequestsSender::Response> scatterGatherUnversionedTargetAllShards( OperationContext* opCtx, - const std::string& dbName, - boost::optional<NamespaceString> nss, + StringData dbName, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy) { - // Some commands, such as $currentOp, operate on a collectionless namespace. If a full namespace - // is specified, its database must match the dbName. - invariant(!nss || (nss->db() == dbName)); - - auto requests = buildUnversionedRequestsForAllShards(opCtx, cmdObj); - - return gatherResponses(opCtx, dbName, readPref, retryPolicy, requests); + return gatherResponses( + opCtx, dbName, readPref, retryPolicy, buildUnversionedRequestsForAllShards(opCtx, cmdObj)); } std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRoutingTable( OperationContext* opCtx, - const std::string& dbName, const NamespaceString& nss, + const CachedCollectionRoutingInfo& routingInfo, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy, const BSONObj& query, const BSONObj& collation) { - // The database in the full namespace must match the dbName. - invariant(nss.db() == dbName); - - auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - auto requests = + const auto requests = buildVersionedRequestsForTargetedShards(opCtx, routingInfo, cmdObj, query, collation); - return gatherResponses(opCtx, dbName, readPref, retryPolicy, requests); + return gatherResponses(opCtx, nss.db(), readPref, retryPolicy, requests); } std::vector<AsyncRequestsSender::Response> scatterGatherOnlyVersionIfUnsharded( OperationContext* opCtx, - const std::string& dbName, const NamespaceString& nss, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy) { - // The database in the full namespace must match the dbName. - invariant(nss.db() == dbName); - auto routingInfo = uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); @@ -251,7 +236,7 @@ std::vector<AsyncRequestsSender::Response> scatterGatherOnlyVersionIfUnsharded( opCtx, routingInfo, cmdObj, BSONObj(), BSONObj()); } - return gatherResponses(opCtx, dbName, readPref, retryPolicy, requests); + return gatherResponses(opCtx, nss.db(), readPref, retryPolicy, requests); } bool appendRawResponses(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_commands_helpers.h b/src/mongo/s/commands/cluster_commands_helpers.h index 10ba26784a4..458e0ac9d3c 100644 --- a/src/mongo/s/commands/cluster_commands_helpers.h +++ b/src/mongo/s/commands/cluster_commands_helpers.h @@ -68,8 +68,7 @@ BSONObj appendShardVersion(BSONObj cmdObj, ChunkVersion version); */ std::vector<AsyncRequestsSender::Response> scatterGatherUnversionedTargetAllShards( OperationContext* opCtx, - const std::string& dbName, - boost::optional<NamespaceString> nss, + StringData dbName, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy); @@ -84,8 +83,8 @@ std::vector<AsyncRequestsSender::Response> scatterGatherUnversionedTargetAllShar */ std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRoutingTable( OperationContext* opCtx, - const std::string& dbName, const NamespaceString& nss, + const CachedCollectionRoutingInfo& routingInfo, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, Shard::RetryPolicy retryPolicy, @@ -105,7 +104,6 @@ std::vector<AsyncRequestsSender::Response> scatterGatherVersionedTargetByRouting */ std::vector<AsyncRequestsSender::Response> scatterGatherOnlyVersionIfUnsharded( OperationContext* opCtx, - const std::string& dbName, const NamespaceString& nss, const BSONObj& cmdObj, const ReadPreferenceSetting& readPref, diff --git a/src/mongo/s/commands/cluster_count_cmd.cpp b/src/mongo/s/commands/cluster_count_cmd.cpp index 794cf1d9fb3..e5ddda0a004 100644 --- a/src/mongo/s/commands/cluster_count_cmd.cpp +++ b/src/mongo/s/commands/cluster_count_cmd.cpp @@ -142,10 +142,12 @@ public: std::vector<AsyncRequestsSender::Response> shardResponses; try { + const auto routingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); shardResponses = scatterGatherVersionedTargetByRoutingTable(opCtx, - dbname, nss, + routingInfo, countCmdObj, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, @@ -251,10 +253,12 @@ public: std::vector<AsyncRequestsSender::Response> shardResponses; try { + const auto routingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); shardResponses = scatterGatherVersionedTargetByRoutingTable(opCtx, - dbname, nss, + routingInfo, explainCmd, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, diff --git a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp index 67c63939043..84274d6f211 100644 --- a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp @@ -73,7 +73,6 @@ public: auto shardResponses = scatterGatherOnlyVersionIfUnsharded( opCtx, - dbName, nss, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/commands/cluster_data_size_cmd.cpp b/src/mongo/s/commands/cluster_data_size_cmd.cpp new file mode 100644 index 00000000000..6cac20332c8 --- /dev/null +++ b/src/mongo/s/commands/cluster_data_size_cmd.cpp @@ -0,0 +1,140 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/s/commands/cluster_commands_helpers.h" +#include "mongo/s/grid.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace { + +class DataSizeCmd : public BasicCommand { +public: + DataSizeCmd() : BasicCommand("dataSize", "datasize") {} + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsFullyQualified(dbname, cmdObj); + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + bool adminOnly() const override { + return false; + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const override { + ActionSet actions; + actions.addAction(ActionType::find); + out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + const NamespaceString nss(parseNs(dbName, cmdObj)); + + auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); + const auto cm = routingInfo.cm(); + + BSONObj min = cmdObj.getObjectField("min"); + BSONObj max = cmdObj.getObjectField("max"); + + if (cm) { + auto keyPattern = cmdObj["keyPattern"]; + + uassert(ErrorCodes::BadValue, + "keyPattern must be empty or must be an object that equals the shard key", + !keyPattern || (keyPattern.type() == Object && + SimpleBSONObjComparator::kInstance.evaluate( + cm->getShardKeyPattern().toBSON() == keyPattern.Obj()))); + + uassert(ErrorCodes::BadValue, + str::stream() << "min value " << min << " does not have shard key", + cm->getShardKeyPattern().isShardKey(min)); + min = cm->getShardKeyPattern().normalizeShardKey(min); + + uassert(ErrorCodes::BadValue, + str::stream() << "max value " << max << " does not have shard key", + cm->getShardKeyPattern().isShardKey(max)); + max = cm->getShardKeyPattern().normalizeShardKey(max); + } + + auto shardResults = scatterGatherVersionedTargetByRoutingTable( + opCtx, + nss, + routingInfo, + CommandHelpers::filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx), + Shard::RetryPolicy::kIdempotent, + {}, + {}); + + // yes these are doubles... + double size = 0; + double numObjects = 0; + int millis = 0; + + for (const auto& shardResult : shardResults) { + const auto shardResponse = uassertStatusOK(std::move(shardResult.swResponse)); + uassertStatusOK(shardResponse.status); + + const auto& res = shardResponse.data; + uassertStatusOK(getStatusFromCommandResult(res)); + + size += res["size"].number(); + numObjects += res["numObjects"].number(); + millis += res["millis"].numberInt(); + } + + result.append("size", size); + result.append("numObjects", numObjects); + result.append("millis", millis); + + return true; + } + +} dataSizeCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_db_stats_cmd.cpp b/src/mongo/s/commands/cluster_db_stats_cmd.cpp index 897d2a6130f..b40fb3dbd98 100644 --- a/src/mongo/s/commands/cluster_db_stats_cmd.cpp +++ b/src/mongo/s/commands/cluster_db_stats_cmd.cpp @@ -124,7 +124,6 @@ public: auto shardResponses = scatterGatherUnversionedTargetAllShards( opCtx, dbName, - boost::none, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent); diff --git a/src/mongo/s/commands/cluster_distinct_cmd.cpp b/src/mongo/s/commands/cluster_distinct_cmd.cpp index 1fb071ea75c..fe77b39aeaa 100644 --- a/src/mongo/s/commands/cluster_distinct_cmd.cpp +++ b/src/mongo/s/commands/cluster_distinct_cmd.cpp @@ -94,10 +94,12 @@ public: std::vector<AsyncRequestsSender::Response> shardResponses; try { + const auto routingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); shardResponses = scatterGatherVersionedTargetByRoutingTable(opCtx, - dbname, nss, + routingInfo, explainCmd, ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, @@ -171,8 +173,8 @@ public: try { shardResponses = scatterGatherVersionedTargetByRoutingTable( opCtx, - dbName, nss, + routingInfo, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, diff --git a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp index e5a546ddc4e..824ddf958b8 100644 --- a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp @@ -78,7 +78,6 @@ public: // receiving its first chunk for the collection (see SERVER-31715). auto shardResponses = scatterGatherOnlyVersionIfUnsharded( opCtx, - dbName, nss, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/commands/cluster_reindex_cmd.cpp b/src/mongo/s/commands/cluster_reindex_cmd.cpp index 9a325330776..573bb3e515c 100644 --- a/src/mongo/s/commands/cluster_reindex_cmd.cpp +++ b/src/mongo/s/commands/cluster_reindex_cmd.cpp @@ -70,12 +70,10 @@ public: const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbName, cmdObj)); - LOG(1) << "reIndex: " << nss << " cmd:" << redact(cmdObj); + const NamespaceString nss(parseNs(dbName, cmdObj)); auto shardResponses = scatterGatherOnlyVersionIfUnsharded( opCtx, - dbName, nss, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/commands/cluster_restart_catalog_command.cpp b/src/mongo/s/commands/cluster_restart_catalog_command.cpp index 228f69aaa2f..949fce3c88c 100644 --- a/src/mongo/s/commands/cluster_restart_catalog_command.cpp +++ b/src/mongo/s/commands/cluster_restart_catalog_command.cpp @@ -34,13 +34,15 @@ namespace mongo { namespace { -/** - * Forwards the testing-only restartCatalog command to all shards. - */ class ClusterRestartCatalogCmd : public BasicCommand { public: ClusterRestartCatalogCmd() : BasicCommand("restartCatalog") {} + std::string help() const override { + return "Internal command for testing only. Forwards the restartCatalog command to all " + "shards."; + } + Status checkAuthForOperation(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj) const override { @@ -68,33 +70,21 @@ public: return false; } - std::string help() const override { - return "restart catalog\n" - "Internal command for testing only. Forwards the restartCatalog command to\n" - "all shards.\n"; - } - bool run(OperationContext* opCtx, const std::string& db, const BSONObj& cmdObj, BSONObjBuilder& result) override { - // This command doesn't operate on a collection namespace, so just pass in an empty - // NamespaceString. - const auto namespaceStringForCommand = boost::none; auto shardResponses = scatterGatherUnversionedTargetAllShards( opCtx, db, - namespaceStringForCommand, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent); - std::string errmsg; - appendRawResponses(opCtx, &errmsg, &result, shardResponses); - // Intentionally not adding the error message to 'result', as it will already contain all // the errors from the shards in a field named 'raw'. - return errmsg.length() > 0 ? false : true; + std::string errmsg; + return appendRawResponses(opCtx, &errmsg, &result, shardResponses); } }; diff --git a/src/mongo/s/commands/cluster_validate_cmd.cpp b/src/mongo/s/commands/cluster_validate_cmd.cpp index 7a63e9a4327..53db0e9f8e3 100644 --- a/src/mongo/s/commands/cluster_validate_cmd.cpp +++ b/src/mongo/s/commands/cluster_validate_cmd.cpp @@ -33,6 +33,7 @@ #include "mongo/db/commands.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/commands/cluster_commands_helpers.h" +#include "mongo/s/grid.h" namespace mongo { namespace { @@ -71,10 +72,12 @@ public: BSONObjBuilder& output) override { const NamespaceString nss(parseNs(dbName, cmdObj)); + const auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); auto results = scatterGatherVersionedTargetByRoutingTable( opCtx, - dbName, nss, + routingInfo, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), Shard::RetryPolicy::kIdempotent, diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp index 54499f66924..c979710fbc9 100644 --- a/src/mongo/s/commands/commands_public.cpp +++ b/src/mongo/s/commands/commands_public.cpp @@ -324,257 +324,6 @@ public: } clusterCopyDBCmd; -class CollectionStats : public PublicGridCommand { -public: - CollectionStats() : PublicGridCommand("collStats", "collstats") {} - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); - } - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::collStats); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - const NamespaceString nss(parseNs(dbName, cmdObj)); - - auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - if (!routingInfo.cm()) { - result.appendBool("sharded", false); - result.append("primary", routingInfo.primaryId().toString()); - return passthrough(opCtx, dbName, routingInfo.primaryId(), cmdObj, result); - } - - const auto cm = routingInfo.cm(); - - result.appendBool("sharded", true); - - BSONObjBuilder shardStats; - std::map<std::string, long long> counts; - std::map<std::string, long long> indexSizes; - - long long unscaledCollSize = 0; - - int nindexes = 0; - bool warnedAboutIndexes = false; - - std::set<ShardId> shardIds; - cm->getAllShardIds(&shardIds); - - for (const auto& shardId : shardIds) { - const auto res = [&] { - const auto shard = - uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardId)); - auto commandResponse = uassertStatusOK(shard->runCommandWithFixedRetryAttempts( - opCtx, - ReadPreferenceSetting::get(opCtx), - dbName, - appendShardVersion(CommandHelpers::filterCommandRequestForPassthrough(cmdObj), - cm->getVersion(shardId)), - Shard::RetryPolicy::kIdempotent)); - - uassertStatusOK(commandResponse.commandStatus); - return commandResponse.response; - }(); - - // We don't know the order that we will encounter the count and size, so we save them - // until we've iterated through all the fields before updating unscaledCollSize - const auto shardObjCount = static_cast<long long>(res["count"].Number()); - long long shardAvgObjSize = 0; - - for (const auto& e : res) { - if (str::equals(e.fieldName(), "ns") || // - str::equals(e.fieldName(), "ok") || // - str::equals(e.fieldName(), "lastExtentSize") || // - str::equals(e.fieldName(), "paddingFactor")) { - continue; - } else if (str::equals(e.fieldName(), "count") || // - str::equals(e.fieldName(), "size") || // - str::equals(e.fieldName(), "storageSize") || // - str::equals(e.fieldName(), "numExtents") || // - str::equals(e.fieldName(), "totalIndexSize")) { - counts[e.fieldName()] += e.numberLong(); - } else if (str::equals(e.fieldName(), "avgObjSize")) { - shardAvgObjSize = e.numberLong(); - } else if (str::equals(e.fieldName(), "indexSizes")) { - BSONObjIterator k(e.Obj()); - while (k.more()) { - BSONElement temp = k.next(); - indexSizes[temp.fieldName()] += temp.numberLong(); - } - } else if (str::equals(e.fieldName(), "userFlags")) { - if (!result.hasField(e.fieldName())) - result.append(e); - } else if (str::equals(e.fieldName(), "capped")) { - if (!result.hasField(e.fieldName())) - result.append(e); - } else if (str::equals(e.fieldName(), "paddingFactorNote")) { - if (!result.hasField(e.fieldName())) - result.append(e); - } else if (str::equals(e.fieldName(), "indexDetails")) { - // skip this field in the rollup - } else if (str::equals(e.fieldName(), "nindexes")) { - int myIndexes = e.numberInt(); - - if (nindexes == 0) { - nindexes = myIndexes; - } else if (nindexes == myIndexes) { - // no-op - } else { - // hopefully this means we're building an index - - if (myIndexes > nindexes) - nindexes = myIndexes; - - if (!warnedAboutIndexes) { - result.append("warning", - "indexes don't all match - ok if ensureIndex is running"); - warnedAboutIndexes = true; - } - } - } else { - warning() << "mongos collstats doesn't know about: " << e.fieldName(); - } - } - shardStats.append(shardId.toString(), res); - unscaledCollSize += shardAvgObjSize * shardObjCount; - } - - result.append("ns", nss.ns()); - - for (const auto& countEntry : counts) { - result.appendNumber(countEntry.first, countEntry.second); - } - - { - BSONObjBuilder ib(result.subobjStart("indexSizes")); - for (const auto& entry : indexSizes) { - ib.appendNumber(entry.first, entry.second); - } - ib.done(); - } - - // The unscaled avgObjSize for each shard is used to get the unscaledCollSize - // because the raw size returned by the shard is affected by the command's - // scale parameter. - if (counts["count"] > 0) - result.append("avgObjSize", (double)unscaledCollSize / (double)counts["count"]); - else - result.append("avgObjSize", 0.0); - - result.append("nindexes", nindexes); - - result.append("nchunks", cm->numChunks()); - result.append("shards", shardStats.obj()); - - return true; - } - -} collectionStatsCmd; - -class DataSizeCmd : public PublicGridCommand { -public: - DataSizeCmd() : PublicGridCommand("dataSize", "datasize") {} - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsFullyQualified(dbname, cmdObj); - } - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - const NamespaceString nss(parseNs(dbName, cmdObj)); - - auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - if (!routingInfo.cm()) { - return passthrough(opCtx, dbName, routingInfo.primaryId(), cmdObj, result); - } - - const auto cm = routingInfo.cm(); - - BSONObj min = cmdObj.getObjectField("min"); - BSONObj max = cmdObj.getObjectField("max"); - BSONObj keyPattern = cmdObj.getObjectField("keyPattern"); - - uassert(13408, - "keyPattern must equal shard key", - SimpleBSONObjComparator::kInstance.evaluate(cm->getShardKeyPattern().toBSON() == - keyPattern)); - uassert(13405, - str::stream() << "min value " << min << " does not have shard key", - cm->getShardKeyPattern().isShardKey(min)); - uassert(13406, - str::stream() << "max value " << max << " does not have shard key", - cm->getShardKeyPattern().isShardKey(max)); - - min = cm->getShardKeyPattern().normalizeShardKey(min); - max = cm->getShardKeyPattern().normalizeShardKey(max); - - // yes these are doubles... - double size = 0; - double numObjects = 0; - int millis = 0; - - std::set<ShardId> shardIds; - cm->getShardIdsForRange(min, max, &shardIds); - - for (const ShardId& shardId : shardIds) { - const auto shardStatus = Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardId); - if (!shardStatus.isOK()) { - continue; - } - - ScopedDbConnection conn(shardStatus.getValue()->getConnString()); - BSONObj res; - bool ok = conn->runCommand( - dbName, CommandHelpers::filterCommandRequestForPassthrough(cmdObj), res); - conn.done(); - - if (!ok) { - CommandHelpers::filterCommandReplyForPassthrough(res, &result); - return false; - } - - size += res["size"].number(); - numObjects += res["numObjects"].number(); - millis += res["millis"].numberInt(); - } - - result.append("size", size); - result.append("numObjects", numObjects); - result.append("millis", millis); - return true; - } - -} dataSizeCmd; - class ConvertToCappedCmd : public NotAllowedOnShardedCollectionCmd { public: ConvertToCappedCmd() : NotAllowedOnShardedCollectionCmd("convertToCapped") {} diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 6a10b1b6856..20e01646cf6 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -609,10 +609,12 @@ void Strategy::explainFind(OperationContext* opCtx, // We will time how long it takes to run the commands on the shards. Timer timer; + const auto routingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, qr.nss())); auto shardResponses = scatterGatherVersionedTargetByRoutingTable(opCtx, - qr.nss().db().toString(), qr.nss(), + routingInfo, explainCmd, readPref, Shard::RetryPolicy::kIdempotent, |