caveman/hunter/src/posts_cache.rs
2022-11-23 23:59:35 +01:00

51 lines
1.3 KiB
Rust

use std::{
collections::{BTreeMap, HashSet},
sync::{Arc, Mutex},
time::{Instant, Duration},
};
/// In-process cache avoids a round-trip to redis for each post
#[derive(Clone)]
pub struct PostsCache {
cache: Arc<Mutex<HashSet<Arc<String>>>>,
ages: Arc<Mutex<BTreeMap<Instant, Arc<String>>>>,
size: usize,
}
impl PostsCache {
pub fn new(size: usize) -> Self {
PostsCache {
cache: Arc::new(Mutex::new(HashSet::new())),
ages: Arc::new(Mutex::new(BTreeMap::new())),
size,
}
}
// returns true if already exists
pub fn insert(&self, k: String) -> bool {
let k = Arc::new(k);
let mut cache = self.cache.lock().expect("cache.lock");
if cache.contains(&k) {
return true;
}
let mut ages = self.ages.lock().expect("ages.lock");
let mut now = Instant::now();
while ages.get(&now).is_some() {
now += Duration::from_millis(1);
}
ages.insert(now, k.clone());
cache.insert(k);
while cache.len() > self.size {
let oldest = ages.keys().cloned().next().expect("ages first");
let oldest_k = ages.remove(&oldest).expect("remove oldest");
cache.remove(&oldest_k);
}
false
}
}