1use std::sync::atomic::{AtomicU64, Ordering};
8
9#[derive(Debug, Default)]
11pub struct CacheStats {
12 hits: AtomicU64,
14 misses: AtomicU64,
16 inserts: AtomicU64,
18 evictions: AtomicU64,
20 expirations: AtomicU64,
22}
23
24impl CacheStats {
25 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn record_hit(&self) {
32 self.hits.fetch_add(1, Ordering::Relaxed);
33 }
34
35 pub fn record_miss(&self) {
37 self.misses.fetch_add(1, Ordering::Relaxed);
38 }
39
40 pub fn record_insert(&self) {
42 self.inserts.fetch_add(1, Ordering::Relaxed);
43 }
44
45 pub fn record_eviction(&self) {
47 self.evictions.fetch_add(1, Ordering::Relaxed);
48 }
49
50 pub fn record_expiration(&self) {
52 self.expirations.fetch_add(1, Ordering::Relaxed);
53 }
54
55 pub fn hits(&self) -> u64 {
57 self.hits.load(Ordering::Relaxed)
58 }
59
60 pub fn misses(&self) -> u64 {
62 self.misses.load(Ordering::Relaxed)
63 }
64
65 pub fn inserts(&self) -> u64 {
67 self.inserts.load(Ordering::Relaxed)
68 }
69
70 pub fn evictions(&self) -> u64 {
72 self.evictions.load(Ordering::Relaxed)
73 }
74
75 pub fn expirations(&self) -> u64 {
77 self.expirations.load(Ordering::Relaxed)
78 }
79
80 pub fn hit_rate(&self) -> f64 {
82 let hits = self.hits();
83 let total = hits + self.misses();
84 if total == 0 {
85 0.0
86 } else {
87 hits as f64 / total as f64
88 }
89 }
90
91 pub fn total_requests(&self) -> u64 {
93 self.hits() + self.misses()
94 }
95
96 pub fn reset(&self) {
98 self.hits.store(0, Ordering::Relaxed);
99 self.misses.store(0, Ordering::Relaxed);
100 self.inserts.store(0, Ordering::Relaxed);
101 self.evictions.store(0, Ordering::Relaxed);
102 self.expirations.store(0, Ordering::Relaxed);
103 }
104
105 pub fn snapshot(&self) -> CacheStatsSnapshot {
107 CacheStatsSnapshot {
108 hits: self.hits(),
109 misses: self.misses(),
110 inserts: self.inserts(),
111 evictions: self.evictions(),
112 expirations: self.expirations(),
113 }
114 }
115}
116
117#[derive(Debug, Clone)]
119pub struct CacheStatsSnapshot {
120 pub hits: u64,
122 pub misses: u64,
124 pub inserts: u64,
126 pub evictions: u64,
128 pub expirations: u64,
130}
131
132impl CacheStatsSnapshot {
133 pub fn hit_rate(&self) -> f64 {
135 let total = self.hits + self.misses;
136 if total == 0 {
137 0.0
138 } else {
139 self.hits as f64 / total as f64
140 }
141 }
142
143 pub fn total_requests(&self) -> u64 {
145 self.hits + self.misses
146 }
147}
148
149impl std::fmt::Display for CacheStatsSnapshot {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(
152 f,
153 "CacheStats {{ hits: {}, misses: {}, hit_rate: {:.2}%, inserts: {}, evictions: {}, expirations: {} }}",
154 self.hits,
155 self.misses,
156 self.hit_rate() * 100.0,
157 self.inserts,
158 self.evictions,
159 self.expirations
160 )
161 }
162}