51 lines
1.3 KiB
Rust
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
|
|
}
|
|
}
|