From c34376156deae34392105ec1d7c948f93655de54 Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 09:26:09 +0000 Subject: [PATCH 1/6] refactor: streamline MetricsCell and enhance documentation Removed the `new` method from `MetricsCell` to simplify its usage, as it is now directly initialized with a `Cell`. Updated the documentation for `metrics_impl.rs` to provide clearer insights into the metrics structures and their visibility, emphasizing the encapsulation of internal metrics management. Added concise summaries for each metrics struct to improve clarity and usability. --- src/metrics/cell.rs | 5 -- src/metrics/metrics_impl.rs | 125 +++++++++++++----------------------- src/policy/s3_fifo.rs | 2 +- 3 files changed, 47 insertions(+), 85 deletions(-) diff --git a/src/metrics/cell.rs b/src/metrics/cell.rs index 2bc0514..d72dac5 100644 --- a/src/metrics/cell.rs +++ b/src/metrics/cell.rs @@ -9,11 +9,6 @@ use std::cell::Cell; pub(crate) struct MetricsCell(Cell); impl MetricsCell { - #[inline] - pub fn new() -> Self { - Self(Cell::new(0)) - } - #[inline] pub fn get(&self) -> u64 { self.0.get() diff --git a/src/metrics/metrics_impl.rs b/src/metrics/metrics_impl.rs index b7f426d..82c25b8 100644 --- a/src/metrics/metrics_impl.rs +++ b/src/metrics/metrics_impl.rs @@ -1,3 +1,16 @@ +//! Concrete metrics recorders for each eviction policy. +//! +//! Each struct accumulates lightweight counters that the corresponding policy +//! increments on its hot path. The [`snapshot`](super::snapshot) module provides +//! read-only, `Copy` snapshots of these counters for bench/test consumption, +//! while [`exporter`](super::exporter) publishes them to monitoring backends. +//! +//! ## Field visibility +//! +//! Fields backed by plain `u64` are `pub` for direct reads. +//! Fields that require interior mutability (recorded through `&self` on read +//! paths) use the crate-internal [`MetricsCell`] and are `pub(crate)`. + use crate::metrics::cell::MetricsCell; use crate::metrics::traits::{ ArcMetricsRecorder, CarMetricsRecorder, ClockMetricsRecorder, ClockProMetricsRecorder, @@ -7,7 +20,8 @@ use crate::metrics::traits::{ S3FifoMetricsRecorder, SlruMetricsRecorder, TwoQMetricsRecorder, }; -#[derive(Debug, Default)] +/// FIFO / insertion-order cache metrics. +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct CacheMetrics { pub get_calls: u64, pub get_hits: u64, @@ -29,7 +43,8 @@ pub struct CacheMetrics { pub(crate) age_rank_found: MetricsCell, } -#[derive(Debug, Default)] +/// LRU (least-recently-used) cache metrics. +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct LruMetrics { pub get_calls: u64, pub get_hits: u64, @@ -50,7 +65,8 @@ pub struct LruMetrics { pub(crate) recency_rank_scan_steps: MetricsCell, } -#[derive(Debug, Default)] +/// LFU (least-frequently-used) cache metrics. +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct LfuMetrics { pub get_calls: u64, pub get_hits: u64, @@ -72,7 +88,8 @@ pub struct LfuMetrics { pub increment_frequency_found: u64, } -#[derive(Debug, Default)] +/// LRU-K (K-distance) cache metrics. +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct LruKMetrics { pub get_calls: u64, pub get_hits: u64, @@ -102,31 +119,6 @@ pub struct LruKMetrics { pub(crate) k_distance_rank_scan_steps: MetricsCell, } -impl CacheMetrics { - pub fn new() -> CacheMetrics { - Self { - get_calls: 0, - get_hits: 0, - get_misses: 0, - insert_calls: 0, - insert_updates: 0, - insert_new: 0, - evict_calls: 0, - evicted_entries: 0, - stale_skips: 0, - evict_scan_steps: 0, - pop_oldest_calls: 0, - pop_oldest_found: 0, - pop_oldest_empty_or_stale: 0, - peek_oldest_calls: MetricsCell::new(), - peek_oldest_found: MetricsCell::new(), - age_rank_calls: MetricsCell::new(), - age_rank_scan_steps: MetricsCell::new(), - age_rank_found: MetricsCell::new(), - } - } -} - impl CoreMetricsRecorder for CacheMetrics { fn record_get_hit(&mut self) { self.get_calls += 1; @@ -185,6 +177,7 @@ impl FifoMetricsRecorder for CacheMetrics { } } +#[doc(hidden)] impl FifoMetricsReadRecorder for &CacheMetrics { fn record_peek_oldest_call(&self) { self.peek_oldest_calls.incr(); @@ -279,6 +272,7 @@ impl LruMetricsRecorder for LruMetrics { } } +#[doc(hidden)] impl LruMetricsReadRecorder for &LruMetrics { fn record_peek_lru_call(&self) { self.peek_lru_calls.incr(); @@ -377,6 +371,7 @@ impl LfuMetricsRecorder for LfuMetrics { } } +#[doc(hidden)] impl LfuMetricsReadRecorder for &LfuMetrics { fn record_peek_lfu_call(&self) { self.peek_lfu_calls.incr(); @@ -505,6 +500,7 @@ impl LruKMetricsRecorder for LruKMetrics { } } +#[doc(hidden)] impl LruKMetricsReadRecorder for &LruKMetrics { fn record_peek_lru_k_call(&self) { self.peek_lru_k_calls.incr(); @@ -535,11 +531,8 @@ impl LruKMetricsReadRecorder for &LruKMetrics { } } -// --------------------------------------------------------------------------- -// CoreOnlyMetrics (LIFO, Random) -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// Minimal metrics for policies with no policy-specific counters (LIFO, Random). +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct CoreOnlyMetrics { pub get_calls: u64, pub get_hits: u64, @@ -578,11 +571,8 @@ impl CoreMetricsRecorder for CoreOnlyMetrics { fn record_clear(&mut self) {} } -// --------------------------------------------------------------------------- -// ArcMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// ARC (adaptive replacement cache) metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct ArcMetrics { pub get_calls: u64, pub get_hits: u64, @@ -652,11 +642,8 @@ impl ArcMetricsRecorder for ArcMetrics { } } -// --------------------------------------------------------------------------- -// CarMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// CAR (clock with adaptive replacement) metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct CarMetrics { pub get_calls: u64, pub get_hits: u64, @@ -722,11 +709,8 @@ impl CarMetricsRecorder for CarMetrics { } } -// --------------------------------------------------------------------------- -// ClockMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// Clock (second-chance) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct ClockMetrics { pub get_calls: u64, pub get_hits: u64, @@ -776,11 +760,8 @@ impl ClockMetricsRecorder for ClockMetrics { } } -// --------------------------------------------------------------------------- -// ClockProMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// Clock-PRO (adaptive hot/cold/test clock) metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct ClockProMetrics { pub get_calls: u64, pub get_hits: u64, @@ -838,11 +819,8 @@ impl ClockProMetricsRecorder for ClockProMetrics { } } -// --------------------------------------------------------------------------- -// MfuMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// MFU (most-frequently-used eviction) metrics. +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct MfuMetrics { pub get_calls: u64, pub get_hits: u64, @@ -908,6 +886,7 @@ impl MfuMetricsRecorder for MfuMetrics { } } +#[doc(hidden)] impl MfuMetricsReadRecorder for &MfuMetrics { fn record_peek_mfu_call(&self) { self.peek_mfu_calls.incr(); @@ -923,11 +902,8 @@ impl MfuMetricsReadRecorder for &MfuMetrics { } } -// --------------------------------------------------------------------------- -// NruMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// NRU (not-recently-used) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct NruMetrics { pub get_calls: u64, pub get_hits: u64, @@ -977,11 +953,8 @@ impl NruMetricsRecorder for NruMetrics { } } -// --------------------------------------------------------------------------- -// SlruMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// SLRU (segmented LRU) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct SlruMetrics { pub get_calls: u64, pub get_hits: u64, @@ -1031,11 +1004,8 @@ impl SlruMetricsRecorder for SlruMetrics { } } -// --------------------------------------------------------------------------- -// TwoQMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default)] +/// Two-Q (A1in/A1out/Am queue) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct TwoQMetrics { pub get_calls: u64, pub get_hits: u64, @@ -1085,11 +1055,8 @@ impl TwoQMetricsRecorder for TwoQMetrics { } } -// --------------------------------------------------------------------------- -// S3FifoMetrics -// --------------------------------------------------------------------------- - -#[derive(Debug, Default, Clone)] +/// S3-FIFO (small/main/ghost queue) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct S3FifoMetrics { pub get_calls: u64, pub get_hits: u64, diff --git a/src/policy/s3_fifo.rs b/src/policy/s3_fifo.rs index 7b76286..c4f899b 100644 --- a/src/policy/s3_fifo.rs +++ b/src/policy/s3_fifo.rs @@ -1528,7 +1528,7 @@ where /// Returns merged performance metrics (inner write-path + concurrent read-path). #[cfg(feature = "metrics")] pub fn metrics(&self) -> S3FifoMetrics { - let mut m = self.inner.read().metrics().clone(); + let mut m = *self.inner.read().metrics(); let rh = self.read_hits.load(Ordering::Relaxed); let rm = self.read_misses.load(Ordering::Relaxed); m.get_hits += rh; From 7d211dfe9900bfb0769d15ceeb885180874ac901 Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 09:32:28 +0000 Subject: [PATCH 2/6] feat: add serde support for cache metrics serialization Introduced optional `serde` dependency for cache metrics snapshots, enabling serialization and deserialization of metrics structures. Enhanced documentation for `CacheMetricsSnapshot` and other metrics structs to clarify their purpose and usage, including examples demonstrating serialization capabilities. This change improves usability and facilitates integration with external systems requiring metrics data in a serialized format. --- Cargo.lock | 1 + Cargo.toml | 2 + src/metrics/snapshot.rs | 101 +++++++++++++++++++++++++++++++++------- 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2560e13..257a2bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,7 @@ dependencies = [ "proptest", "quick_cache", "rustc-hash 2.1.1", + "serde", "serde_json", ] diff --git a/Cargo.toml b/Cargo.toml index 7f9efbb..fdf4a21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ crate-type = ["lib"] [features] default = ["policy-s3-fifo", "policy-lru", "policy-fast-lru", "policy-lru-k", "policy-clock"] metrics = [] +serde = ["dep:serde"] concurrency = ["parking_lot"] # Eviction policy feature flags. Enable only the policies you need for smaller builds. @@ -81,6 +82,7 @@ policy-nru = [] [dependencies] parking_lot = { version = "0.12", optional = true } rustc-hash = "2.1" +serde = { version = "1", features = ["derive"], optional = true } [dev-dependencies] bench-support = { path = "bench-support" } diff --git a/src/metrics/snapshot.rs b/src/metrics/snapshot.rs index e928465..1504958 100644 --- a/src/metrics/snapshot.rs +++ b/src/metrics/snapshot.rs @@ -1,4 +1,28 @@ -#[derive(Debug, Default, Clone, Copy)] +//! Point-in-time snapshots of cache metrics counters. +//! +//! Each eviction policy has a dedicated snapshot struct that captures both the +//! core counters (gets, inserts, evictions) and policy-specific signals at the +//! moment [`MetricsSnapshotProvider::snapshot`] is called. +//! +//! Snapshots are cheap `Copy` value types intended for assertion in tests, +//! export via [`PrometheusTextExporter`], or ad-hoc inspection with `Debug`. +//! +//! ## Example +//! +//! ``` +//! use cachekit::metrics::snapshot::CoreOnlyMetricsSnapshot; +//! +//! let snap = CoreOnlyMetricsSnapshot::default(); +//! assert_eq!(snap.get_calls, snap.get_hits + snap.get_misses); +//! ``` +//! +//! [`MetricsSnapshotProvider::snapshot`]: crate::metrics::traits::MetricsSnapshotProvider::snapshot +//! [`PrometheusTextExporter`]: crate::metrics::exporter::PrometheusTextExporter + +/// FIFO / insertion-order cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CacheMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -10,8 +34,10 @@ pub struct CacheMetricsSnapshot { pub evict_calls: u64, pub evicted_entries: u64, - pub stale_skips: u64, // queue entries popped that were already removed from map - pub evict_scan_steps: u64, // how many pop_front iterations inside eviction + /// Queue entries popped that were already removed from the map. + pub stale_skips: u64, + /// How many `pop_front` iterations inside a single eviction call. + pub evict_scan_steps: u64, pub pop_oldest_calls: u64, pub pop_oldest_found: u64, @@ -24,13 +50,18 @@ pub struct CacheMetricsSnapshot { pub age_rank_found: u64, pub age_rank_scan_steps: u64, - // gauges captured at snapshot time + /// Current number of entries in the cache (gauge). pub cache_len: usize, + /// Current length of the insertion-order queue (gauge). pub insertion_order_len: usize, + /// Configured maximum capacity (gauge). pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// LRU (Least Recently Used) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LruMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -57,7 +88,10 @@ pub struct LruMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// LFU (Least Frequently Used) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LfuMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -85,7 +119,10 @@ pub struct LfuMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// LRU-K cache metrics, combining standard LRU counters with K-distance tracking. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LruKMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -122,7 +159,10 @@ pub struct LruKMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// Core-only metrics for policies that add no policy-specific counters. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CoreOnlyMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -139,7 +179,10 @@ pub struct CoreOnlyMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// ARC (Adaptive Replacement Cache) metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ArcMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -164,7 +207,10 @@ pub struct ArcMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// CAR (Clock with Adaptive Replacement) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CarMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -188,7 +234,10 @@ pub struct CarMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// CLOCK cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ClockMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -208,7 +257,10 @@ pub struct ClockMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// CLOCK-Pro cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ClockProMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -230,7 +282,10 @@ pub struct ClockProMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// MFU (Most Frequently Used) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MfuMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -254,7 +309,10 @@ pub struct MfuMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// NRU (Not Recently Used) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NruMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -274,7 +332,10 @@ pub struct NruMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// SLRU (Segmented LRU) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SlruMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -294,7 +355,10 @@ pub struct SlruMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// 2Q (Two-Queue) cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TwoQMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, @@ -314,7 +378,10 @@ pub struct TwoQMetricsSnapshot { pub capacity: usize, } -#[derive(Debug, Default, Clone, Copy)] +/// S3-FIFO cache metrics. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct S3FifoMetricsSnapshot { pub get_calls: u64, pub get_hits: u64, From 0d1521c5c20a89f6c7722b8cb798b7f4fbb0f2ee Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 09:37:21 +0000 Subject: [PATCH 3/6] docs: enhance metrics traits documentation with examples and clarity Added example usage for `CoreMetricsRecorder` and its related traits, improving the documentation for cache metrics. Clarified the purpose of each metrics trait and their relationships, including references to mutable and read-only counterparts. This change enhances usability and understanding of the metrics system within the cache library. --- src/metrics/traits.rs | 85 +++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/metrics/traits.rs b/src/metrics/traits.rs index 91db925..7f8ffd8 100644 --- a/src/metrics/traits.rs +++ b/src/metrics/traits.rs @@ -43,8 +43,25 @@ //! - **Environment split**: //! - Production: use lightweight recorders + exporters. //! - Bench/Test: use snapshot providers + resettable metrics. +//! +//! ## Example +//! +//! ``` +//! use cachekit::metrics::traits::{CoreMetricsRecorder, MetricsSnapshotProvider}; +//! +//! fn run_workload(m: &mut M) { +//! m.record_get_hit(); +//! m.record_get_miss(); +//! m.record_insert_call(); +//! m.record_insert_new(); +//! } +//! ``` /// Common counters for any cache policy. +/// +/// Every policy-specific recorder (e.g. [`FifoMetricsRecorder`], +/// [`LruMetricsRecorder`]) extends this trait so shared hit/miss/insert/evict +/// counters are always available. pub trait CoreMetricsRecorder { fn record_get_hit(&mut self); fn record_get_miss(&mut self); @@ -57,6 +74,8 @@ pub trait CoreMetricsRecorder { } /// Metrics for FIFO behavior (insertion order). +/// +/// See also [`FifoMetricsReadRecorder`] for read-only (`&self`) counters. pub trait FifoMetricsRecorder: CoreMetricsRecorder { fn record_evict_scan_step(&mut self); fn record_stale_skip(&mut self); @@ -65,10 +84,12 @@ pub trait FifoMetricsRecorder: CoreMetricsRecorder { fn record_pop_oldest_empty_or_stale(&mut self); } -/// Read-only FIFO metrics for &self methods (uses interior mutability). +/// Read-only FIFO metrics for `&self` methods (uses interior mutability). /// /// Use this for cache operations that only take `&self` (e.g., `peek_oldest`, /// `age_rank`) where a mutable recorder is not available. +/// +/// See also [`FifoMetricsRecorder`] for the mutable counterpart. pub trait FifoMetricsReadRecorder { fn record_peek_oldest_call(&self); fn record_peek_oldest_found(&self); @@ -78,6 +99,8 @@ pub trait FifoMetricsReadRecorder { } /// Metrics for LRU behavior (recency order). +/// +/// See also [`LruMetricsReadRecorder`] for read-only (`&self`) counters. pub trait LruMetricsRecorder: CoreMetricsRecorder { fn record_pop_lru_call(&mut self); fn record_pop_lru_found(&mut self); @@ -90,7 +113,9 @@ pub trait LruMetricsRecorder: CoreMetricsRecorder { fn record_recency_rank_scan_step(&mut self); } -/// Read-only LRU metrics for &self methods (uses interior mutability). +/// Read-only LRU metrics for `&self` methods (uses interior mutability). +/// +/// See also [`LruMetricsRecorder`] for the mutable counterpart. pub trait LruMetricsReadRecorder { fn record_peek_lru_call(&self); fn record_peek_lru_found(&self); @@ -100,6 +125,8 @@ pub trait LruMetricsReadRecorder { } /// Metrics for LFU behavior (frequency order). +/// +/// See also [`LfuMetricsReadRecorder`] for read-only (`&self`) counters. pub trait LfuMetricsRecorder: CoreMetricsRecorder { fn record_pop_lfu_call(&mut self); fn record_pop_lfu_found(&mut self); @@ -113,7 +140,9 @@ pub trait LfuMetricsRecorder: CoreMetricsRecorder { fn record_increment_frequency_found(&mut self); } -/// Read-only LFU metrics for &self methods (uses interior mutability). +/// Read-only LFU metrics for `&self` methods (uses interior mutability). +/// +/// See also [`LfuMetricsRecorder`] for the mutable counterpart. pub trait LfuMetricsReadRecorder { fn record_peek_lfu_call(&self); fn record_peek_lfu_found(&self); @@ -122,6 +151,9 @@ pub trait LfuMetricsReadRecorder { } /// Metrics for LRU-K behavior (K-distance order). +/// +/// Extends [`LruMetricsRecorder`] with backward K-distance counters. +/// See also [`LruKMetricsReadRecorder`] for read-only (`&self`) counters. pub trait LruKMetricsRecorder: LruMetricsRecorder { fn record_pop_lru_k_call(&mut self); fn record_pop_lru_k_found(&mut self); @@ -134,7 +166,9 @@ pub trait LruKMetricsRecorder: LruMetricsRecorder { fn record_k_distance_rank_scan_step(&mut self); } -/// Read-only LRU-K metrics for &self methods (uses interior mutability). +/// Read-only LRU-K metrics for `&self` methods (uses interior mutability). +/// +/// See also [`LruKMetricsRecorder`] for the mutable counterpart. pub trait LruKMetricsReadRecorder { fn record_peek_lru_k_call(&self); fn record_peek_lru_k_found(&self); @@ -181,6 +215,8 @@ pub trait ClockProMetricsRecorder: CoreMetricsRecorder { } /// Metrics for MFU behavior (most frequently used eviction). +/// +/// See also [`MfuMetricsReadRecorder`] for read-only (`&self`) counters. pub trait MfuMetricsRecorder: CoreMetricsRecorder { fn record_pop_mfu_call(&mut self); fn record_pop_mfu_found(&mut self); @@ -190,7 +226,9 @@ pub trait MfuMetricsRecorder: CoreMetricsRecorder { fn record_frequency_found(&mut self); } -/// Read-only MFU metrics for &self methods (uses interior mutability). +/// Read-only MFU metrics for `&self` methods (uses interior mutability). +/// +/// See also [`MfuMetricsRecorder`] for the mutable counterpart. pub trait MfuMetricsReadRecorder { fn record_peek_mfu_call(&self); fn record_peek_mfu_found(&self); @@ -226,43 +264,26 @@ pub trait S3FifoMetricsRecorder: CoreMetricsRecorder { } /// Snapshot provider for bench/testing. +/// +/// Returns a point-in-time copy of all counters as a snapshot struct `S`. +/// Pair with [`MetricsReset`] to clear counters between iterations, or +/// with [`MetricsExporter`] to publish snapshots to a monitoring backend. pub trait MetricsSnapshotProvider { fn snapshot(&self) -> S; } /// Reset metrics between tests or benchmark iterations. +/// +/// Typically used alongside [`MetricsSnapshotProvider`] to isolate +/// measurements across successive runs. pub trait MetricsReset { fn reset_metrics(&self); } /// Export/publish metrics to production monitoring backends. +/// +/// Consumes a snapshot produced by [`MetricsSnapshotProvider::snapshot`] +/// and writes it to an external system (e.g. Prometheus, StatsD). pub trait MetricsExporter { fn export(&self, snapshot: &S); } - -/// Shared counters for any policy. -#[derive(Debug, Default, Clone, Copy)] -pub struct CoreMetricsSnapshot { - pub get_calls: u64, - pub get_hits: u64, - pub get_misses: u64, - pub insert_calls: u64, - pub insert_updates: u64, - pub insert_new: u64, - pub evict_calls: u64, - pub evicted_entries: u64, -} - -/// FIFO-specific snapshot composed from the core snapshot. -#[derive(Debug, Default, Clone, Copy)] -pub struct FifoMetricsSnapshot { - pub core: CoreMetricsSnapshot, - pub pop_oldest_calls: u64, - pub pop_oldest_found: u64, - pub pop_oldest_empty_or_stale: u64, - pub peek_oldest_calls: u64, - pub peek_oldest_found: u64, - pub age_rank_calls: u64, - pub age_rank_found: u64, - pub age_rank_scan_steps: u64, -} From 67f45f1a5a4b4802bb2df36d2b68872ad382f35e Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 12:46:18 +0000 Subject: [PATCH 4/6] fix: update frequency buckets iteration method for accuracy Replaced the `iter_entries` method with `iter` in the frequency buckets property tests to ensure accurate minimum frequency calculations. This change aligns with recent updates to the `FrequencyBuckets` module, enhancing consistency and correctness in the test implementation. --- fuzz/fuzz_targets/frequency_buckets_property_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/frequency_buckets_property_tests.rs b/fuzz/fuzz_targets/frequency_buckets_property_tests.rs index 15c2f79..ef00e28 100644 --- a/fuzz/fuzz_targets/frequency_buckets_property_tests.rs +++ b/fuzz/fuzz_targets/frequency_buckets_property_tests.rs @@ -101,7 +101,7 @@ fn test_min_freq_accuracy(data: &[u8]) { // Compute actual minimum frequency let mut actual_min: Option = None; - for (_, meta) in buckets.iter_entries() { + for (_, meta) in buckets.iter() { actual_min = match actual_min { None => Some(meta.freq), Some(min) => Some(min.min(meta.freq)), From 0a7d7b867446e74fdad0c42df42153b1dec756c0 Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 13:57:06 +0000 Subject: [PATCH 5/6] docs: clarify MetricsCell usage in metrics_impl.rs Updated the documentation for `MetricsCell` in `metrics_impl.rs` to include a direct reference to its location within the module. This change enhances clarity regarding the internal structure and visibility of the metrics management system, ensuring users understand the encapsulation of internal metrics management. --- src/metrics/metrics_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/metrics_impl.rs b/src/metrics/metrics_impl.rs index 82c25b8..4b475cf 100644 --- a/src/metrics/metrics_impl.rs +++ b/src/metrics/metrics_impl.rs @@ -9,7 +9,7 @@ //! //! Fields backed by plain `u64` are `pub` for direct reads. //! Fields that require interior mutability (recorded through `&self` on read -//! paths) use the crate-internal [`MetricsCell`] and are `pub(crate)`. +//! paths) use the crate-internal [`MetricsCell`](super::cell::MetricsCell) and are `pub(crate)`. use crate::metrics::cell::MetricsCell; use crate::metrics::traits::{ From b12c507c2697559b240f79a59a0d8f73f20febf8 Mon Sep 17 00:00:00 2001 From: Thomas Korrison Date: Sun, 22 Mar 2026 13:57:23 +0000 Subject: [PATCH 6/6] docs: refine MetricsCell documentation in metrics_impl.rs Updated the documentation for `MetricsCell` in `metrics_impl.rs` to remove redundant phrasing, enhancing clarity regarding its usage and visibility within the module. This change aims to improve understanding of the internal metrics management system. --- src/metrics/metrics_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/metrics_impl.rs b/src/metrics/metrics_impl.rs index 4b475cf..b8eecae 100644 --- a/src/metrics/metrics_impl.rs +++ b/src/metrics/metrics_impl.rs @@ -9,7 +9,7 @@ //! //! Fields backed by plain `u64` are `pub` for direct reads. //! Fields that require interior mutability (recorded through `&self` on read -//! paths) use the crate-internal [`MetricsCell`](super::cell::MetricsCell) and are `pub(crate)`. +//! paths) use the crate-internal `MetricsCell` and are `pub(crate)`. use crate::metrics::cell::MetricsCell; use crate::metrics::traits::{