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}