diff --git a/daemon/buckets.cc b/daemon/buckets.cc index cd50308f78..edad0bcd4f 100644 --- a/daemon/buckets.cc +++ b/daemon/buckets.cc @@ -112,6 +112,10 @@ nlohmann::json Bucket::to_json() const { void Bucket::addMeteringMetrics(const BucketStatCollector& collector) const { using namespace cb::stats; + // engine-related metering (e.g., disk usage) + getEngine().get_prometheus_stats( + collector, cb::prometheus::MetricGroup::Metering); + // metering collector.addStat(Key::meter_ru_total, read_units_used); collector.addStat(Key::meter_wu_total, write_units_used); diff --git a/engines/ep/src/ep_bucket.cc b/engines/ep/src/ep_bucket.cc index 5c0df44ae8..b2f60a3e66 100644 --- a/engines/ep/src/ep_bucket.cc +++ b/engines/ep/src/ep_bucket.cc @@ -1516,17 +1516,23 @@ bool EPBucket::updateCompactionTasks(Vbid vbid) { return false; } -cb::engine_errc EPBucket::getFileStats(const BucketStatCollector& collector) { +DBFileInfo EPBucket::getAggregatedFileInfo() { const auto numShards = vbMap.getNumShards(); DBFileInfo totalInfo; for (uint16_t shardId = 0; shardId < numShards; shardId++) { - const auto dbInfo = - getRWUnderlyingByShard(shardId)->getAggrDbFileInfo(); - totalInfo.spaceUsed += dbInfo.spaceUsed; - totalInfo.fileSize += dbInfo.fileSize; - totalInfo.prepareBytes += dbInfo.prepareBytes; + totalInfo += getRWUnderlyingByShard(shardId)->getAggrDbFileInfo(); } + return totalInfo; +} + +uint64_t EPBucket::getTotalDiskSize() { + using namespace cb::stats; + return getAggregatedFileInfo().fileSize; +} + +cb::engine_errc EPBucket::getFileStats(const BucketStatCollector& collector) { + auto totalInfo = getAggregatedFileInfo(); using namespace cb::stats; collector.addStat(Key::ep_db_data_size, totalInfo.getEstimatedLiveData()); diff --git a/engines/ep/src/ep_bucket.h b/engines/ep/src/ep_bucket.h index dde1dbaa50..a7a220359a 100644 --- a/engines/ep/src/ep_bucket.h +++ b/engines/ep/src/ep_bucket.h @@ -165,6 +165,8 @@ class EPBucket : public KVBucket { */ bool updateCompactionTasks(Vbid vbid); + uint64_t getTotalDiskSize() override; + cb::engine_errc getFileStats(const BucketStatCollector& collector) override; cb::engine_errc getPerVBucketDiskStats(const CookieIface* cookie, @@ -449,6 +451,12 @@ class EPBucket : public KVBucket { */ void updateCompactionConcurrency(); + /** + * Return disk usage information, summed across all shards. + * @return total file info + */ + DBFileInfo getAggregatedFileInfo(); + /** * Max number of backill items in a single flusher batch before we split * into multiple batches. Actual batch size may be larger as we will not diff --git a/engines/ep/src/ep_engine.cc b/engines/ep/src/ep_engine.cc index 844632555e..cfdb469e58 100644 --- a/engines/ep/src/ep_engine.cc +++ b/engines/ep/src/ep_engine.cc @@ -378,6 +378,8 @@ cb::engine_errc EventuallyPersistentEngine::get_prometheus_stats( return doMetricGroupHigh(collector); case MetricGroup::Low: return doMetricGroupLow(collector); + case MetricGroup::Metering: + return doMetricGroupMetering(collector); case MetricGroup::All: // nothing currently requests All metrics at this level, so rather // than leaving an unused impl to rot, defer until it is actually @@ -432,6 +434,15 @@ cb::engine_errc EventuallyPersistentEngine::doMetricGroupLow( return doConnAggStats(collector, ":"); } +cb::engine_errc EventuallyPersistentEngine::doMetricGroupMetering( + const BucketStatCollector& collector) { + using namespace cb::stats; + // equivalent to Key::ep_db_file_size but named to match metering + // requirements. + collector.addStat(Key::storage, kvBucket->getTotalDiskSize()); + return cb::engine_errc::success; +} + cb::engine_errc EventuallyPersistentEngine::store( const CookieIface& cookie, ItemIface& itm, diff --git a/engines/ep/src/ep_engine.h b/engines/ep/src/ep_engine.h index 1418d0db3f..566fd0265c 100644 --- a/engines/ep/src/ep_engine.h +++ b/engines/ep/src/ep_engine.h @@ -1137,6 +1137,16 @@ class EventuallyPersistentEngine : public EngineIface, public DcpIface { */ cb::engine_errc doMetricGroupLow(const BucketStatCollector& collector); + /** + * Get metrics from this engine for the "Metering" group. + * + * These metrics will only be gathered if DeploymentModel::Serverless. + * These are likely to be scraped frequently, so should not be too + * numerous or expensive. + */ + cb::engine_errc doMetricGroupMetering( + const BucketStatCollector& collector); + void addLookupResult(const CookieIface* cookie, std::unique_ptr result); diff --git a/engines/ep/src/ephemeral_bucket.h b/engines/ep/src/ephemeral_bucket.h index f8dd0275d6..6465b90041 100644 --- a/engines/ep/src/ephemeral_bucket.h +++ b/engines/ep/src/ephemeral_bucket.h @@ -46,6 +46,11 @@ class EphemeralBucket : public KVBucket { return cb::mcbp::Status::NotSupported; } + uint64_t getTotalDiskSize() override { + // Ephemeral buckets do not use a notable amount of disk space. + return 0; + } + /// File stats not supported for Ephemeral buckets. cb::engine_errc getFileStats( const BucketStatCollector& collector) override { diff --git a/engines/ep/src/kv_bucket_iface.h b/engines/ep/src/kv_bucket_iface.h index 8dd8a129cf..c158e7d75a 100644 --- a/engines/ep/src/kv_bucket_iface.h +++ b/engines/ep/src/kv_bucket_iface.h @@ -379,6 +379,13 @@ class KVBucketIface { const BucketStatCollector& collector, cb::prometheus::MetricGroup metricGroup) = 0; + /** + * Get the total disk space used by this bucket. + * + * @return number of bytes of disk space used + */ + virtual uint64_t getTotalDiskSize() = 0; + /** * Get file statistics * diff --git a/engines/ep/src/kvstore/kvstore.cc b/engines/ep/src/kvstore/kvstore.cc index 34ffd28cec..ed7042251b 100644 --- a/engines/ep/src/kvstore/kvstore.cc +++ b/engines/ep/src/kvstore/kvstore.cc @@ -778,3 +778,10 @@ std::ostream& operator<<(std::ostream& os, return os << "INVALID GetCollectionStatsStatus value:" << static_cast(status); } + +DBFileInfo& DBFileInfo::operator+=(const DBFileInfo& other) { + spaceUsed += other.spaceUsed; + fileSize += other.fileSize; + prepareBytes += other.prepareBytes; + return *this; +} diff --git a/engines/ep/src/kvstore/kvstore.h b/engines/ep/src/kvstore/kvstore.h index dbf07f186f..35e9ec5ac0 100644 --- a/engines/ep/src/kvstore/kvstore.h +++ b/engines/ep/src/kvstore/kvstore.h @@ -369,6 +369,8 @@ struct DBFileInfo { } return spaceUsed; } + + DBFileInfo& operator+=(const DBFileInfo& other); }; struct vbucket_state; diff --git a/include/statistics/cardinality.h b/include/statistics/cardinality.h index d5caf23b2a..f68ce334f4 100644 --- a/include/statistics/cardinality.h +++ b/include/statistics/cardinality.h @@ -19,5 +19,5 @@ namespace cb::prometheus { * * all: include metrics from both low and high cardinality groups (e.g., * for code shared with cbstats) */ -enum class MetricGroup { Low, High, All }; +enum class MetricGroup { Low, High, Metering, All }; } // namespace cb::prometheus \ No newline at end of file diff --git a/statistics/stat_definitions.json b/statistics/stat_definitions.json index 6ea2fdad82..0f5a78d4fb 100644 --- a/statistics/stat_definitions.json +++ b/statistics/stat_definitions.json @@ -2580,5 +2580,10 @@ "key": "throttle_count_total", "unit": "none", "description": "Total number of times requests have been throttled for a bucket since reset" + }, + { + "key": "storage", + "unit": "bytes", + "description": "Total bytes on disk used by a bucket" } ] \ No newline at end of file