#![allow(clippy::cast_precision_loss)]
use serde::{Deserialize, Serialize};
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Default)]
pub struct CacheMetrics {
pub hits: AtomicU64,
pub misses: AtomicU64,
pub evictions: AtomicU64,
pub memory_bytes: AtomicU64,
}
impl CacheMetrics {
pub fn new() -> Self {
Self::default()
}
pub fn record_hit(&self) {
self.hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_miss(&self) {
self.misses.fetch_add(1, Ordering::Relaxed);
}
pub fn record_eviction(&self, count: u64) {
self.evictions.fetch_add(count, Ordering::Relaxed);
}
pub fn update_memory(&self, bytes: u64) {
self.memory_bytes.store(bytes, Ordering::Relaxed);
}
pub fn add_memory(&self, bytes: u64) {
self.memory_bytes.fetch_add(bytes, Ordering::Relaxed);
}
pub fn sub_memory(&self, bytes: u64) {
self.memory_bytes.fetch_sub(bytes, Ordering::Relaxed);
}
pub fn reset(&self) {
self.hits.store(0, Ordering::Relaxed);
self.misses.store(0, Ordering::Relaxed);
self.evictions.store(0, Ordering::Relaxed);
self.memory_bytes.store(0, Ordering::Relaxed);
}
pub fn report(&self) -> MetricsReport {
let hits = self.hits.load(Ordering::Relaxed);
let misses = self.misses.load(Ordering::Relaxed);
let total_requests = hits + misses;
MetricsReport {
hit_rate: if total_requests > 0 {
hits as f64 / total_requests as f64
} else {
0.0
},
miss_rate: if total_requests > 0 {
misses as f64 / total_requests as f64
} else {
0.0
},
total_requests,
hits,
misses,
evictions: self.evictions.load(Ordering::Relaxed),
memory_usage_bytes: self.memory_bytes.load(Ordering::Relaxed),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricsReport {
pub hit_rate: f64,
pub miss_rate: f64,
pub total_requests: u64,
pub hits: u64,
pub misses: u64,
pub evictions: u64,
pub memory_usage_bytes: u64,
}
impl MetricsReport {
pub fn memory_usage_mb(&self) -> f64 {
self.memory_usage_bytes as f64 / (1024.0 * 1024.0)
}
pub fn is_effective(&self, threshold: f64) -> bool {
self.hit_rate >= threshold
}
}