Skip to main content

crates_docs/tools/docs/cache/
stats.rs

1//! Cache statistics for document cache
2
3use std::sync::atomic::{AtomicU64, Ordering};
4
5/// Cache statistics tracker
6#[derive(Debug, Default)]
7pub struct CacheStats {
8    /// Total cache hits
9    hits: AtomicU64,
10    /// Total cache misses
11    misses: AtomicU64,
12    /// Total cache sets
13    sets: AtomicU64,
14}
15
16impl CacheStats {
17    /// Create new cache statistics
18    #[must_use]
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    /// Record a cache hit
24    pub fn record_hit(&self) {
25        self.hits.fetch_add(1, Ordering::Relaxed);
26    }
27
28    /// Record a cache miss
29    pub fn record_miss(&self) {
30        self.misses.fetch_add(1, Ordering::Relaxed);
31    }
32
33    /// Record a cache set operation
34    pub fn record_set(&self) {
35        self.sets.fetch_add(1, Ordering::Relaxed);
36    }
37
38    /// Get total hits
39    #[must_use]
40    pub fn hits(&self) -> u64 {
41        self.hits.load(Ordering::Relaxed)
42    }
43
44    /// Get total misses
45    #[must_use]
46    pub fn misses(&self) -> u64 {
47        self.misses.load(Ordering::Relaxed)
48    }
49
50    /// Get total sets
51    #[must_use]
52    pub fn sets(&self) -> u64 {
53        self.sets.load(Ordering::Relaxed)
54    }
55
56    /// Get total requests (hits + misses)
57    #[must_use]
58    pub fn total_requests(&self) -> u64 {
59        self.hits() + self.misses()
60    }
61
62    /// Calculate hit rate (0.0 to 1.0)
63    #[must_use]
64    #[allow(clippy::cast_precision_loss)]
65    pub fn hit_rate(&self) -> f64 {
66        let total = self.total_requests();
67        if total == 0 {
68            return 0.0;
69        }
70        self.hits() as f64 / total as f64
71    }
72
73    /// Reset all statistics
74    pub fn reset(&self) {
75        self.hits.store(0, Ordering::Relaxed);
76        self.misses.store(0, Ordering::Relaxed);
77        self.sets.store(0, Ordering::Relaxed);
78    }
79}
80
81impl Clone for CacheStats {
82    fn clone(&self) -> Self {
83        Self {
84            hits: AtomicU64::new(self.hits.load(Ordering::Relaxed)),
85            misses: AtomicU64::new(self.misses.load(Ordering::Relaxed)),
86            sets: AtomicU64::new(self.sets.load(Ordering::Relaxed)),
87        }
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_cache_stats_new() {
97        let stats = CacheStats::new();
98        assert_eq!(stats.hits(), 0);
99        assert_eq!(stats.misses(), 0);
100        assert_eq!(stats.sets(), 0);
101    }
102
103    #[test]
104    fn test_cache_stats_record() {
105        let stats = CacheStats::new();
106
107        stats.record_hit();
108        stats.record_hit();
109        stats.record_miss();
110        stats.record_set();
111        stats.record_set();
112        stats.record_set();
113
114        assert_eq!(stats.hits(), 2);
115        assert_eq!(stats.misses(), 1);
116        assert_eq!(stats.sets(), 3);
117    }
118
119    #[test]
120    fn test_cache_stats_hit_rate() {
121        let stats = CacheStats::new();
122
123        assert!((stats.hit_rate() - 0.0).abs() < f64::EPSILON);
124
125        stats.record_hit();
126        stats.record_hit();
127        stats.record_miss();
128
129        let rate = stats.hit_rate();
130        assert!((rate - 0.666_666_666_666_666_6).abs() < f64::EPSILON);
131    }
132
133    #[test]
134    fn test_cache_stats_total_requests() {
135        let stats = CacheStats::new();
136
137        stats.record_hit();
138        stats.record_hit();
139        stats.record_miss();
140        stats.record_miss();
141
142        assert_eq!(stats.total_requests(), 4);
143    }
144
145    #[test]
146    fn test_cache_stats_reset() {
147        let stats = CacheStats::new();
148
149        stats.record_hit();
150        stats.record_miss();
151        stats.record_set();
152
153        stats.reset();
154
155        assert_eq!(stats.hits(), 0);
156        assert_eq!(stats.misses(), 0);
157        assert_eq!(stats.sets(), 0);
158    }
159
160    #[test]
161    fn test_cache_stats_clone() {
162        let stats = CacheStats::new();
163        stats.record_hit();
164        stats.record_miss();
165
166        let cloned = stats.clone();
167
168        assert_eq!(cloned.hits(), 1);
169        assert_eq!(cloned.misses(), 1);
170    }
171}