use std::fmt;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Instant;
use crossbeam_utils::CachePadded;
#[derive(Debug)]
pub struct Metrics {
pub(crate) hits: CachePadded<AtomicU64>,
pub(crate) misses: CachePadded<AtomicU64>,
pub(crate) inserts: CachePadded<AtomicU64>,
pub(crate) updates: CachePadded<AtomicU64>,
pub(crate) invalidations: CachePadded<AtomicU64>,
pub(crate) evicted_by_capacity: CachePadded<AtomicU64>,
pub(crate) evicted_by_ttl: CachePadded<AtomicU64>,
pub(crate) evicted_by_tti: CachePadded<AtomicU64>,
pub(crate) keys_admitted: CachePadded<AtomicU64>,
pub(crate) keys_rejected: CachePadded<AtomicU64>,
pub(crate) current_cost: CachePadded<AtomicU64>,
pub(crate) total_cost_added: CachePadded<AtomicU64>,
created_at: Instant,
}
impl Default for Metrics {
fn default() -> Self {
Self {
hits: CachePadded::new(AtomicU64::new(0)),
misses: CachePadded::new(AtomicU64::new(0)),
inserts: CachePadded::new(AtomicU64::new(0)),
updates: CachePadded::new(AtomicU64::new(0)),
invalidations: CachePadded::new(AtomicU64::new(0)),
evicted_by_capacity: CachePadded::new(AtomicU64::new(0)),
evicted_by_ttl: CachePadded::new(AtomicU64::new(0)),
evicted_by_tti: CachePadded::new(AtomicU64::new(0)),
keys_admitted: CachePadded::new(AtomicU64::new(0)),
keys_rejected: CachePadded::new(AtomicU64::new(0)),
current_cost: CachePadded::new(AtomicU64::new(0)),
total_cost_added: CachePadded::new(AtomicU64::new(0)),
created_at: Instant::now(), }
}
}
impl Metrics {
pub(crate) fn new() -> Self {
Self::default()
}
pub(crate) fn snapshot(&self) -> MetricsSnapshot {
let hits = self.hits.load(Ordering::Relaxed);
let misses = self.misses.load(Ordering::Relaxed);
let total_lookups = hits + misses;
MetricsSnapshot {
hits,
misses,
hit_ratio: if total_lookups == 0 {
0.0
} else {
hits as f64 / total_lookups as f64
},
inserts: self.inserts.load(Ordering::Relaxed),
updates: self.updates.load(Ordering::Relaxed),
invalidations: self.invalidations.load(Ordering::Relaxed),
evicted_by_capacity: self.evicted_by_capacity.load(Ordering::Relaxed),
evicted_by_ttl: self.evicted_by_ttl.load(Ordering::Relaxed),
evicted_by_tti: self.evicted_by_tti.load(Ordering::Relaxed),
keys_admitted: self.keys_admitted.load(Ordering::Relaxed),
keys_rejected: self.keys_rejected.load(Ordering::Relaxed),
current_cost: self.current_cost.load(Ordering::Relaxed),
total_cost_added: self.total_cost_added.load(Ordering::Relaxed),
uptime_secs: self.created_at.elapsed().as_secs(),
}
}
}
#[derive(Clone)]
pub struct MetricsSnapshot {
pub hits: u64,
pub misses: u64,
pub hit_ratio: f64,
pub inserts: u64,
pub updates: u64,
pub invalidations: u64,
pub evicted_by_capacity: u64,
pub evicted_by_ttl: u64,
pub evicted_by_tti: u64,
pub keys_admitted: u64,
pub keys_rejected: u64,
pub current_cost: u64,
pub total_cost_added: u64,
pub uptime_secs: u64,
}
impl fmt::Debug for MetricsSnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MetricsSnapshot")
.field("hits", &self.hits)
.field("misses", &self.misses)
.field("hit_ratio", &format!("{:.2}%", self.hit_ratio * 100.0))
.field("inserts", &self.inserts)
.field("updates", &self.updates)
.field("invalidations", &self.invalidations)
.field("evicted_by_capacity", &self.evicted_by_capacity)
.field("evicted_by_ttl", &self.evicted_by_ttl)
.field("evicted_by_tti", &self.evicted_by_tti)
.field("keys_admitted", &self.keys_admitted)
.field("keys_rejected", &self.keys_rejected)
.field("current_cost", &self.current_cost)
.field("total_cost_added", &self.total_cost_added)
.field("uptime_secs", &self.uptime_secs)
.finish()
}
}