use std::sync::Arc;
use std::time::{SystemTime, Duration, UNIX_EPOCH};
use tokio::sync::RwLock;
use tonic::Status;
#[derive(Clone)]
pub struct CacheManager {
ttl: Option<u64>,
last_eviction: Arc<RwLock<SystemTime>>,
min_eviction_interval: Duration,
}
impl CacheManager {
pub fn new(ttl: Option<u64>) -> Self {
Self {
ttl,
last_eviction: Arc::new(RwLock::new(SystemTime::now())),
min_eviction_interval: Duration::from_secs(60), }
}
pub fn set_min_eviction_interval(&mut self, interval: Duration) {
self.min_eviction_interval = interval;
}
pub async fn should_evict(&self) -> Result<Option<i64>, Status> {
match self.ttl {
None | Some(0) => Ok(None), Some(ttl) => {
let now = SystemTime::now();
let last = *self.last_eviction.read().await;
if now.duration_since(last).unwrap_or(Duration::from_secs(0)) < self.min_eviction_interval {
return Ok(None);
}
let cutoff = now
.duration_since(UNIX_EPOCH)
.map_err(|e| Status::internal(e.to_string()))?
.as_secs() as i64
- ttl as i64;
*self.last_eviction.write().await = now;
Ok(Some(cutoff))
}
}
}
pub fn eviction_query(&self, cutoff: i64) -> String {
format!(
"DELETE FROM metrics USING (
SELECT timestamp
FROM metrics
WHERE timestamp < {}
LIMIT 10000
) as expired
WHERE metrics.timestamp = expired.timestamp",
cutoff
)
}
}
#[async_trait::async_trait]
pub trait CacheEviction {
async fn execute_eviction(&self, query: &str) -> Result<(), Status>;
}