Skip to main content

agentic_forge_core/cache/
metrics.rs

1//! Cache metrics — hit rate, size, evictions.
2
3use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
4
5pub struct CacheMetrics {
6    hit_count: AtomicU64,
7    miss_count: AtomicU64,
8    eviction_count: AtomicU64,
9    current_size: AtomicUsize,
10}
11
12impl CacheMetrics {
13    pub fn new() -> Self {
14        Self {
15            hit_count: AtomicU64::new(0),
16            miss_count: AtomicU64::new(0),
17            eviction_count: AtomicU64::new(0),
18            current_size: AtomicUsize::new(0),
19        }
20    }
21
22    pub fn record_hit(&self) {
23        self.hit_count.fetch_add(1, Ordering::Relaxed);
24    }
25
26    pub fn record_miss(&self) {
27        self.miss_count.fetch_add(1, Ordering::Relaxed);
28    }
29
30    pub fn record_eviction(&self) {
31        self.eviction_count.fetch_add(1, Ordering::Relaxed);
32    }
33
34    pub fn set_size(&self, size: usize) {
35        self.current_size.store(size, Ordering::Relaxed);
36    }
37
38    pub fn hits(&self) -> u64 {
39        self.hit_count.load(Ordering::Relaxed)
40    }
41
42    pub fn misses(&self) -> u64 {
43        self.miss_count.load(Ordering::Relaxed)
44    }
45
46    pub fn evictions(&self) -> u64 {
47        self.eviction_count.load(Ordering::Relaxed)
48    }
49
50    pub fn size(&self) -> usize {
51        self.current_size.load(Ordering::Relaxed)
52    }
53
54    pub fn total_requests(&self) -> u64 {
55        self.hits() + self.misses()
56    }
57
58    pub fn hit_rate(&self) -> f64 {
59        let total = self.total_requests();
60        if total == 0 {
61            return 0.0;
62        }
63        self.hits() as f64 / total as f64
64    }
65
66    pub fn reset(&self) {
67        self.hit_count.store(0, Ordering::Relaxed);
68        self.miss_count.store(0, Ordering::Relaxed);
69        self.eviction_count.store(0, Ordering::Relaxed);
70    }
71}
72
73impl Default for CacheMetrics {
74    fn default() -> Self {
75        Self::new()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_metrics_initial() {
85        let m = CacheMetrics::new();
86        assert_eq!(m.hits(), 0);
87        assert_eq!(m.misses(), 0);
88        assert_eq!(m.hit_rate(), 0.0);
89    }
90
91    #[test]
92    fn test_metrics_hit_rate() {
93        let m = CacheMetrics::new();
94        m.record_hit();
95        m.record_hit();
96        m.record_miss();
97        assert!((m.hit_rate() - 0.6667).abs() < 0.01);
98    }
99
100    #[test]
101    fn test_metrics_reset() {
102        let m = CacheMetrics::new();
103        m.record_hit();
104        m.record_miss();
105        m.reset();
106        assert_eq!(m.total_requests(), 0);
107    }
108
109    #[test]
110    fn test_metrics_evictions() {
111        let m = CacheMetrics::new();
112        m.record_eviction();
113        m.record_eviction();
114        assert_eq!(m.evictions(), 2);
115    }
116}