use std::time::Duration;
use super::collector::CacheTelemetryCollector;
use super::types::{calculate_percentiles, CacheEventType};
impl CacheTelemetryCollector {
pub fn byte_hit_ratio(&self) -> f64 {
let events = self
.recent_events
.lock()
.expect("lock should not be poisoned");
let mut hit_bytes: u64 = 0;
let mut total_bytes: u64 = 0;
for event in events.iter() {
if let Some(size) = event.size_bytes {
total_bytes += size as u64;
if event.event_type == CacheEventType::Hit {
hit_bytes += size as u64;
}
}
}
if total_bytes == 0 {
0.0
} else {
hit_bytes as f64 / total_bytes as f64
}
}
pub fn p95_latency_ns(&self) -> f64 {
let histogram = self
.latency_histogram
.lock()
.expect("lock should not be poisoned");
if histogram.is_empty() {
return 0.0;
}
let percentiles = calculate_percentiles(&histogram);
percentiles.1 * 1_000.0
}
pub fn p99_latency_ns(&self) -> f64 {
let histogram = self
.latency_histogram
.lock()
.expect("lock should not be poisoned");
if histogram.is_empty() {
return 0.0;
}
let percentiles = calculate_percentiles(&histogram);
percentiles.2 * 1_000.0
}
pub fn p50_latency_us(&self) -> f64 {
let histogram = self
.latency_histogram
.lock()
.expect("lock should not be poisoned");
if histogram.is_empty() {
return 0.0;
}
calculate_percentiles(&histogram).0
}
pub fn p95_latency_us(&self) -> f64 {
let histogram = self
.latency_histogram
.lock()
.expect("lock should not be poisoned");
if histogram.is_empty() {
return 0.0;
}
calculate_percentiles(&histogram).1
}
pub fn p99_latency_us(&self) -> f64 {
let histogram = self
.latency_histogram
.lock()
.expect("lock should not be poisoned");
if histogram.is_empty() {
return 0.0;
}
calculate_percentiles(&histogram).2
}
pub fn total_requests(&self) -> u64 {
let metrics = self
.current_metrics
.lock()
.expect("lock should not be poisoned");
metrics.hits + metrics.misses
}
pub fn current_hit_ratio(&self) -> f64 {
let metrics = self
.current_metrics
.lock()
.expect("lock should not be poisoned");
let total = metrics.hits + metrics.misses;
if total == 0 {
0.0
} else {
metrics.hits as f64 / total as f64
}
}
pub fn avg_hit_latency_us(&self) -> f64 {
self.current_metrics
.lock()
.expect("lock should not be poisoned")
.avg_hit_latency_us
}
pub fn avg_miss_latency_us(&self) -> f64 {
self.current_metrics
.lock()
.expect("lock should not be poisoned")
.avg_miss_latency_us
}
pub fn eviction_rate_per_sec(&self) -> f64 {
let metrics = self
.current_metrics
.lock()
.expect("lock should not be poisoned");
let elapsed = metrics.window_start.elapsed();
let secs = elapsed.as_secs_f64();
if secs <= 0.0 {
0.0
} else {
metrics.evictions as f64 / secs
}
}
pub fn latency_histogram_snapshot(&self) -> std::collections::HashMap<u64, u64> {
self.latency_histogram
.lock()
.expect("lock should not be poisoned")
.clone()
}
pub fn has_latency_data(&self) -> bool {
!self
.latency_histogram
.lock()
.expect("lock should not be poisoned")
.is_empty()
}
pub fn inject_latency_sample(&self, latency: Duration) {
self.record_latency(latency);
}
}