1use std::sync::atomic::{AtomicU64, Ordering};
4
5#[derive(Debug, Default)]
9pub struct CacheStats {
10 snapshots_set: AtomicU64,
12 snapshot_hits: AtomicU64,
14 snapshot_misses: AtomicU64,
16 snapshots_cleared: AtomicU64,
18 notifications_sent: AtomicU64,
20}
21
22impl CacheStats {
23 pub fn new() -> Self {
25 Self::default()
26 }
27
28 #[inline]
30 pub fn record_set(&self) {
31 self.snapshots_set.fetch_add(1, Ordering::Relaxed);
32 }
33
34 #[inline]
36 pub fn record_hit(&self) {
37 self.snapshot_hits.fetch_add(1, Ordering::Relaxed);
38 }
39
40 #[inline]
42 pub fn record_miss(&self) {
43 self.snapshot_misses.fetch_add(1, Ordering::Relaxed);
44 }
45
46 #[inline]
48 pub fn record_clear(&self) {
49 self.snapshots_cleared.fetch_add(1, Ordering::Relaxed);
50 }
51
52 #[inline]
54 pub fn record_notifications(&self, count: u64) {
55 self.notifications_sent.fetch_add(count, Ordering::Relaxed);
56 }
57
58 #[inline]
60 pub fn snapshots_set(&self) -> u64 {
61 self.snapshots_set.load(Ordering::Relaxed)
62 }
63
64 #[inline]
66 pub fn snapshot_hits(&self) -> u64 {
67 self.snapshot_hits.load(Ordering::Relaxed)
68 }
69
70 #[inline]
72 pub fn snapshot_misses(&self) -> u64 {
73 self.snapshot_misses.load(Ordering::Relaxed)
74 }
75
76 #[inline]
78 pub fn snapshots_cleared(&self) -> u64 {
79 self.snapshots_cleared.load(Ordering::Relaxed)
80 }
81
82 #[inline]
84 pub fn notifications_sent(&self) -> u64 {
85 self.notifications_sent.load(Ordering::Relaxed)
86 }
87
88 pub fn hit_rate(&self) -> f64 {
90 let hits = self.snapshot_hits() as f64;
91 let total = hits + self.snapshot_misses() as f64;
92 if total == 0.0 {
93 0.0
94 } else {
95 hits / total
96 }
97 }
98
99 pub fn reset(&self) {
101 self.snapshots_set.store(0, Ordering::Relaxed);
102 self.snapshot_hits.store(0, Ordering::Relaxed);
103 self.snapshot_misses.store(0, Ordering::Relaxed);
104 self.snapshots_cleared.store(0, Ordering::Relaxed);
105 self.notifications_sent.store(0, Ordering::Relaxed);
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn cache_stats_basic() {
115 let stats = CacheStats::new();
116
117 stats.record_set();
118 stats.record_hit();
119 stats.record_hit();
120 stats.record_miss();
121
122 assert_eq!(stats.snapshots_set(), 1);
123 assert_eq!(stats.snapshot_hits(), 2);
124 assert_eq!(stats.snapshot_misses(), 1);
125 let expected = 2.0_f64 / 3.0;
127 assert!((stats.hit_rate() - expected).abs() < f64::EPSILON * 10.0,
128 "hit_rate {} should be approximately {}", stats.hit_rate(), expected);
129 }
130
131 #[test]
132 fn cache_stats_reset() {
133 let stats = CacheStats::new();
134 stats.record_set();
135 stats.reset();
136 assert_eq!(stats.snapshots_set(), 0);
137 }
138}