summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Graetzer <simon.gratzer@mongodb.com>2021-10-11 09:37:14 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-10-11 10:02:02 +0000
commitb6963bac9386ae403088a118d861e6e8c6560d59 (patch)
tree8e52fc3b492d01a69ff1a63c18880a60406bad6c
parent3f3fae26a8abfc9e107baf028f966f3d93f116ce (diff)
downloadmongo-b6963bac9386ae403088a118d861e6e8c6560d59.tar.gz
SERVER-60507 ClusterStatistics need to provide collection level size statistics
-rw-r--r--src/mongo/db/s/balancer/cluster_statistics.cpp42
-rw-r--r--src/mongo/db/s/balancer/cluster_statistics.h19
-rw-r--r--src/mongo/db/s/balancer/cluster_statistics_impl.cpp23
-rw-r--r--src/mongo/db/s/balancer/cluster_statistics_impl.h6
-rw-r--r--src/mongo/s/shard_util.cpp37
-rw-r--r--src/mongo/s/shard_util.h13
6 files changed, 124 insertions, 16 deletions
diff --git a/src/mongo/db/s/balancer/cluster_statistics.cpp b/src/mongo/db/s/balancer/cluster_statistics.cpp
index df276f8baf3..b9fffb0af51 100644
--- a/src/mongo/db/s/balancer/cluster_statistics.cpp
+++ b/src/mongo/db/s/balancer/cluster_statistics.cpp
@@ -34,6 +34,15 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
+namespace {
+uint64_t convertMBToBytes(uint64_t inMB) {
+ if (inMB > std::numeric_limits<uint64_t>::max() / (1024 * 1024)) {
+ return std::numeric_limits<uint64_t>::max();
+ }
+ return inMB * 1024 * 1024;
+}
+} // namespace
+
namespace mongo {
ClusterStatistics::ClusterStatistics() = default;
@@ -41,31 +50,46 @@ ClusterStatistics::ClusterStatistics() = default;
ClusterStatistics::~ClusterStatistics() = default;
ClusterStatistics::ShardStatistics::ShardStatistics(ShardId inShardId,
- uint64_t inMaxSizeMB,
- uint64_t inCurrSizeMB,
+ uint64_t inMaxSizeBytes,
+ uint64_t inCurrSizeBytes,
bool inIsDraining,
std::set<std::string> inShardTags,
- std::string inMongoVersion)
+ std::string inMongoVersion,
+ use_bytes_t t)
: shardId(std::move(inShardId)),
- maxSizeMB(inMaxSizeMB),
- currSizeMB(inCurrSizeMB),
+ maxSizeBytes(inMaxSizeBytes),
+ currSizeBytes(inCurrSizeBytes),
isDraining(inIsDraining),
shardTags(std::move(inShardTags)),
mongoVersion(std::move(inMongoVersion)) {}
+ClusterStatistics::ShardStatistics::ShardStatistics(ShardId inShardId,
+ uint64_t inMaxSizeMB,
+ uint64_t inCurrSizeMB,
+ bool inIsDraining,
+ std::set<std::string> inShardTags,
+ std::string inMongoVersion)
+ : ShardStatistics(inShardId,
+ convertMBToBytes(inMaxSizeMB),
+ convertMBToBytes(inCurrSizeMB),
+ inIsDraining,
+ std::move(inShardTags),
+ std::move(inMongoVersion),
+ use_bytes_t{}) {}
+
bool ClusterStatistics::ShardStatistics::isSizeMaxed() const {
- if (!maxSizeMB || !currSizeMB) {
+ if (!maxSizeBytes || !currSizeBytes) {
return false;
}
- return currSizeMB >= maxSizeMB;
+ return currSizeBytes >= maxSizeBytes;
}
BSONObj ClusterStatistics::ShardStatistics::toBSON() const {
BSONObjBuilder builder;
builder.append("id", shardId.toString());
- builder.append("maxSizeMB", static_cast<long long>(maxSizeMB));
- builder.append("currSizeMB", static_cast<long long>(currSizeMB));
+ builder.append("maxSizeMB", static_cast<long long>(maxSizeBytes / 1024 / 1024));
+ builder.append("currSizeMB", static_cast<long long>(currSizeBytes / 1024 / 1024));
builder.append("draining", isDraining);
if (!shardTags.empty()) {
BSONArrayBuilder arrayBuilder(builder.subarrayStart("tags"));
diff --git a/src/mongo/db/s/balancer/cluster_statistics.h b/src/mongo/db/s/balancer/cluster_statistics.h
index 32f6cb9f7c5..71c7ce9484f 100644
--- a/src/mongo/db/s/balancer/cluster_statistics.h
+++ b/src/mongo/db/s/balancer/cluster_statistics.h
@@ -58,6 +58,18 @@ public:
*/
struct ShardStatistics {
public:
+ // hack so we do not accidentally miss code using MB
+ struct use_bytes_t {
+ explicit use_bytes_t() = default;
+ };
+ ShardStatistics(ShardId shardId,
+ uint64_t maxSizeBytes,
+ uint64_t currSizeBytes,
+ bool isDraining,
+ std::set<std::string> shardTags,
+ std::string mongoVersion,
+ use_bytes_t t);
+
ShardStatistics(ShardId shardId,
uint64_t maxSizeMB,
uint64_t currSizeMB,
@@ -80,10 +92,10 @@ public:
ShardId shardId;
// The maximum storage size allowed for the shard. Zero means no maximum specified.
- uint64_t maxSizeMB{0};
+ uint64_t maxSizeBytes{0};
// The current storage size of the shard.
- uint64_t currSizeMB{0};
+ uint64_t currSizeBytes{0};
// Whether the shard is in draining mode
bool isDraining{false};
@@ -103,6 +115,9 @@ public:
*/
virtual StatusWith<std::vector<ShardStatistics>> getStats(OperationContext* opCtx) = 0;
+ virtual StatusWith<std::vector<ShardStatistics>> getCollStats(OperationContext* opCtx,
+ NamespaceString const& ns) = 0;
+
protected:
ClusterStatistics();
};
diff --git a/src/mongo/db/s/balancer/cluster_statistics_impl.cpp b/src/mongo/db/s/balancer/cluster_statistics_impl.cpp
index 289f6517de6..495e8a77774 100644
--- a/src/mongo/db/s/balancer/cluster_statistics_impl.cpp
+++ b/src/mongo/db/s/balancer/cluster_statistics_impl.cpp
@@ -89,7 +89,6 @@ StatusWith<std::string> retrieveShardMongoDVersion(OperationContext* opCtx, Shar
return version;
}
-
} // namespace
using ShardStatistics = ClusterStatistics::ShardStatistics;
@@ -99,6 +98,16 @@ ClusterStatisticsImpl::ClusterStatisticsImpl(BalancerRandomSource& random) : _ra
ClusterStatisticsImpl::~ClusterStatisticsImpl() = default;
StatusWith<std::vector<ShardStatistics>> ClusterStatisticsImpl::getStats(OperationContext* opCtx) {
+ return _getStats(opCtx, boost::none);
+}
+
+StatusWith<std::vector<ShardStatistics>> ClusterStatisticsImpl::getCollStats(
+ OperationContext* opCtx, NamespaceString const& ns) {
+ return _getStats(opCtx, ns);
+}
+
+StatusWith<std::vector<ShardStatistics>> ClusterStatisticsImpl::_getStats(
+ OperationContext* opCtx, boost::optional<NamespaceString> ns) {
// Get a list of all the shards that are participating in this balance round along with any
// maximum allowed quotas and current utilization. We get the latter by issuing
// db.serverStatus() (mem.mapped) to all shards.
@@ -118,10 +127,13 @@ StatusWith<std::vector<ShardStatistics>> ClusterStatisticsImpl::getStats(Operati
for (const auto& shard : shards) {
const auto shardSizeStatus = [&]() -> StatusWith<long long> {
+ if (ns) {
+ return shardutil::retrieveCollectionShardSize(opCtx, shard.getName(), *ns);
+ }
+ // optimization for the case where the balancer does not care about the dataSize
if (!shard.getMaxSizeMB()) {
return 0;
}
-
return shardutil::retrieveTotalShardSize(opCtx, shard.getName());
}();
@@ -155,11 +167,12 @@ StatusWith<std::vector<ShardStatistics>> ClusterStatisticsImpl::getStats(Operati
}
stats.emplace_back(shard.getName(),
- shard.getMaxSizeMB(),
- shardSizeStatus.getValue() / 1024 / 1024,
+ shard.getMaxSizeMB() * 1024 * 1024,
+ shardSizeStatus.getValue(),
shard.getDraining(),
std::move(shardTags),
- std::move(mongoDVersion));
+ std::move(mongoDVersion),
+ ShardStatistics::use_bytes_t{});
}
return stats;
diff --git a/src/mongo/db/s/balancer/cluster_statistics_impl.h b/src/mongo/db/s/balancer/cluster_statistics_impl.h
index b9d5a1e2830..56037628a47 100644
--- a/src/mongo/db/s/balancer/cluster_statistics_impl.h
+++ b/src/mongo/db/s/balancer/cluster_statistics_impl.h
@@ -46,7 +46,13 @@ public:
StatusWith<std::vector<ShardStatistics>> getStats(OperationContext* opCtx) override;
+ StatusWith<std::vector<ShardStatistics>> getCollStats(OperationContext* opCtx,
+ NamespaceString const& ns) override;
+
private:
+ StatusWith<std::vector<ShardStatistics>> _getStats(OperationContext* opCtx,
+ boost::optional<NamespaceString> ns);
+
// Source of randomness when metadata needs to be randomized.
BalancerRandomSource& _random;
};
diff --git a/src/mongo/s/shard_util.cpp b/src/mongo/s/shard_util.cpp
index c53c1b8af2f..84e2d5cfcc0 100644
--- a/src/mongo/s/shard_util.cpp
+++ b/src/mongo/s/shard_util.cpp
@@ -90,6 +90,43 @@ StatusWith<long long> retrieveTotalShardSize(OperationContext* opCtx, const Shar
return totalSizeElem.numberLong();
}
+StatusWith<long long> retrieveCollectionShardSize(OperationContext* opCtx,
+ const ShardId& shardId,
+ NamespaceString const& ns,
+ bool estimate) {
+ auto shardStatus = Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardId);
+ if (!shardStatus.isOK()) {
+ return shardStatus.getStatus();
+ }
+
+ const Minutes maxTimeMSOverride{10};
+ const auto cmdObj = BSON("dataSize" << ns.ns() << "estimate" << estimate);
+ auto statStatus = shardStatus.getValue()->runCommandWithFixedRetryAttempts(
+ opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryPreferred},
+ ns.db().toString(),
+ cmdObj,
+ maxTimeMSOverride,
+ Shard::RetryPolicy::kIdempotent);
+
+ auto stat = Shard::CommandResponse::getEffectiveStatus(statStatus);
+ if (!stat.isOK()) {
+ if (stat == ErrorCodes::NamespaceNotFound) {
+ return 0;
+ }
+ return stat;
+ }
+
+
+ BSONElement sizeElem = statStatus.getValue().response["size"];
+ if (!sizeElem.isNumber()) {
+ return {ErrorCodes::NoSuchKey, "size field not found in dataSize"};
+ }
+
+ return sizeElem.safeNumberLong();
+}
+
+
StatusWith<std::vector<BSONObj>> selectChunkSplitPoints(OperationContext* opCtx,
const ShardId& shardId,
const NamespaceString& nss,
diff --git a/src/mongo/s/shard_util.h b/src/mongo/s/shard_util.h
index 7c0ce16fa8b..3152558df4d 100644
--- a/src/mongo/s/shard_util.h
+++ b/src/mongo/s/shard_util.h
@@ -62,6 +62,19 @@ namespace shardutil {
StatusWith<long long> retrieveTotalShardSize(OperationContext* opCtx, const ShardId& shardId);
/**
+ * Executes the dataSize command against the specified shard and obtains the total data
+ * size for the collection in bytes (essentially, the dataSize field).
+ *
+ * Returns OK with the total size in bytes or an error. Known errors are:
+ * ShardNotFound if shard by that id is not available on the registry
+ * NoSuchKey if the total shard size could not be retrieved
+ */
+StatusWith<long long> retrieveCollectionShardSize(OperationContext* opCtx,
+ const ShardId& shardId,
+ NamespaceString const& ns,
+ bool estimate = true);
+
+/**
* Ask the specified shard to figure out the split points for a given chunk.
*
* shardId The shard id to query.