Skip to main content

axess_cache/
stats.rs

1//! Observability counters for [`ClockTtlCache`](crate::ClockTtlCache).
2//! [`CacheStats`] is the `Copy` snapshot returned to callers;
3//! `CacheCounters` is the internal atomic-backed live shape.
4
5use std::sync::atomic::{AtomicU64, Ordering};
6
7/// Counters reported by [`ClockTtlCache::stats`](crate::ClockTtlCache::stats).
8/// Monotonic since construction (or the most recent `reset_stats` call);
9/// returned by value so callers own a snapshot, not a reference into the
10/// live atomics.
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
12pub struct CacheStats {
13    /// Successful `get` hits. TTL-expired entries evicted on access count
14    /// as misses, not hits.
15    pub hits: u64,
16    /// `get` calls that returned `None` (key absent or expired). Includes
17    /// single-flight cache lookups inside `get_or_try_insert_with`.
18    pub misses: u64,
19    /// Successful inserts (fresh and overwriting).
20    pub inserts: u64,
21    /// Entries evicted by LRU capacity pressure during inserts.
22    pub capacity_evictions: u64,
23    /// Entries removed by explicit `invalidate` / `invalidate_by` /
24    /// `invalidate_all` / `cleanup_expired` calls.
25    pub invalidations: u64,
26    /// Concurrent `get_or_try_insert_with` calls that joined an in-flight
27    /// load instead of starting their own. High values mean duplicate
28    /// fetches successfully avoided.
29    pub single_flight_joins: u64,
30    /// `get_or_try_insert_with` fetcher invocations that returned an
31    /// error. The cell is removed on error so subsequent callers retry
32    /// rather than re-await a known-failing future.
33    pub single_flight_errors: u64,
34}
35
36/// Live atomic counters backing [`CacheStats`]. Internal; surfaced only
37/// via the [`CacheStats`] snapshot.
38#[derive(Default)]
39pub(crate) struct CacheCounters {
40    pub(crate) hits: AtomicU64,
41    pub(crate) misses: AtomicU64,
42    pub(crate) inserts: AtomicU64,
43    pub(crate) capacity_evictions: AtomicU64,
44    pub(crate) invalidations: AtomicU64,
45    pub(crate) single_flight_joins: AtomicU64,
46    pub(crate) single_flight_errors: AtomicU64,
47}
48
49impl CacheCounters {
50    pub(crate) fn snapshot(&self) -> CacheStats {
51        CacheStats {
52            hits: self.hits.load(Ordering::Relaxed),
53            misses: self.misses.load(Ordering::Relaxed),
54            inserts: self.inserts.load(Ordering::Relaxed),
55            capacity_evictions: self.capacity_evictions.load(Ordering::Relaxed),
56            invalidations: self.invalidations.load(Ordering::Relaxed),
57            single_flight_joins: self.single_flight_joins.load(Ordering::Relaxed),
58            single_flight_errors: self.single_flight_errors.load(Ordering::Relaxed),
59        }
60    }
61
62    pub(crate) fn reset(&self) {
63        self.hits.store(0, Ordering::Relaxed);
64        self.misses.store(0, Ordering::Relaxed);
65        self.inserts.store(0, Ordering::Relaxed);
66        self.capacity_evictions.store(0, Ordering::Relaxed);
67        self.invalidations.store(0, Ordering::Relaxed);
68        self.single_flight_joins.store(0, Ordering::Relaxed);
69        self.single_flight_errors.store(0, Ordering::Relaxed);
70    }
71}