use std::sync::atomic::{AtomicU64, Ordering};
use super::stats::{CategoryCounts, GraphCacheStats};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum CacheCategory {
SourceProjection,
ExactGraph,
SelectedIndex,
DerivedProduct,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum CacheEvent {
Hit,
Miss,
Eviction,
}
#[derive(Default)]
struct CategoryCounters {
hits: AtomicU64,
misses: AtomicU64,
evictions: AtomicU64,
}
impl CategoryCounters {
fn counter(&self, event: CacheEvent) -> &AtomicU64 {
match event {
CacheEvent::Hit => &self.hits,
CacheEvent::Miss => &self.misses,
CacheEvent::Eviction => &self.evictions,
}
}
fn counts(&self) -> CategoryCounts {
CategoryCounts::new(
self.hits.load(Ordering::Relaxed),
self.misses.load(Ordering::Relaxed),
self.evictions.load(Ordering::Relaxed),
)
}
}
#[derive(Default)]
pub(crate) struct CacheCounters {
source_projections: CategoryCounters,
exact_graphs: CategoryCounters,
selected_indexes: CategoryCounters,
derived_products: CategoryCounters,
}
impl CacheCounters {
pub(crate) fn record(&self, category: CacheCategory, event: CacheEvent, amount: u64) {
match amount {
0 => (),
counted => saturate(self.category(category).counter(event), counted),
}
}
pub(crate) fn snapshot(&self) -> GraphCacheStats {
GraphCacheStats::new(
self.category(CacheCategory::SourceProjection).counts(),
self.category(CacheCategory::ExactGraph).counts(),
self.category(CacheCategory::SelectedIndex).counts(),
self.category(CacheCategory::DerivedProduct).counts(),
)
}
fn category(&self, category: CacheCategory) -> &CategoryCounters {
match category {
CacheCategory::SourceProjection => &self.source_projections,
CacheCategory::ExactGraph => &self.exact_graphs,
CacheCategory::SelectedIndex => &self.selected_indexes,
CacheCategory::DerivedProduct => &self.derived_products,
}
}
}
fn saturate(counter: &AtomicU64, amount: u64) {
let mut held = counter.load(Ordering::Relaxed);
while let Err(current) = counter.compare_exchange_weak(
held,
held.saturating_add(amount),
Ordering::Relaxed,
Ordering::Relaxed,
) {
held = current;
}
}