use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Default)]
pub struct CacheStats {
snapshots_set: AtomicU64,
snapshot_hits: AtomicU64,
snapshot_misses: AtomicU64,
snapshots_cleared: AtomicU64,
notifications_sent: AtomicU64,
}
impl CacheStats {
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn record_set(&self) {
self.snapshots_set.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn record_hit(&self) {
self.snapshot_hits.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn record_miss(&self) {
self.snapshot_misses.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn record_clear(&self) {
self.snapshots_cleared.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn record_notifications(&self, count: u64) {
self.notifications_sent.fetch_add(count, Ordering::Relaxed);
}
#[inline]
pub fn snapshots_set(&self) -> u64 {
self.snapshots_set.load(Ordering::Relaxed)
}
#[inline]
pub fn snapshot_hits(&self) -> u64 {
self.snapshot_hits.load(Ordering::Relaxed)
}
#[inline]
pub fn snapshot_misses(&self) -> u64 {
self.snapshot_misses.load(Ordering::Relaxed)
}
#[inline]
pub fn snapshots_cleared(&self) -> u64 {
self.snapshots_cleared.load(Ordering::Relaxed)
}
#[inline]
pub fn notifications_sent(&self) -> u64 {
self.notifications_sent.load(Ordering::Relaxed)
}
pub fn hit_rate(&self) -> f64 {
let hits = self.snapshot_hits() as f64;
let total = hits + self.snapshot_misses() as f64;
if total == 0.0 {
0.0
} else {
hits / total
}
}
pub fn reset(&self) {
self.snapshots_set.store(0, Ordering::Relaxed);
self.snapshot_hits.store(0, Ordering::Relaxed);
self.snapshot_misses.store(0, Ordering::Relaxed);
self.snapshots_cleared.store(0, Ordering::Relaxed);
self.notifications_sent.store(0, Ordering::Relaxed);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_stats_basic() {
let stats = CacheStats::new();
stats.record_set();
stats.record_hit();
stats.record_hit();
stats.record_miss();
assert_eq!(stats.snapshots_set(), 1);
assert_eq!(stats.snapshot_hits(), 2);
assert_eq!(stats.snapshot_misses(), 1);
let expected = 2.0_f64 / 3.0;
assert!((stats.hit_rate() - expected).abs() < f64::EPSILON * 10.0,
"hit_rate {} should be approximately {}", stats.hit_rate(), expected);
}
#[test]
fn cache_stats_reset() {
let stats = CacheStats::new();
stats.record_set();
stats.reset();
assert_eq!(stats.snapshots_set(), 0);
}
}