use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::time::Instant;
use super::super::{Entry, Meta, UnloadPolicy};
use super::Store;
#[cfg(feature = "events")]
use super::super::{HoldError, HoldEvent};
impl<T> Store<T>
where
T: Clone + Send + Sync,
{
pub fn replace_all(&self, entries: HashMap<String, (T, PathBuf, UnloadPolicy)>) {
let provided_keys: HashSet<String> = entries.keys().cloned().collect();
let mut new_entries: HashMap<String, Entry<T>> = HashMap::new();
for (key, (value, source, policy)) in entries {
let version = self.version.fetch_add(1, Ordering::SeqCst) + 1;
let meta = Meta {
source,
loaded_at: Instant::now(),
version,
policy,
};
new_entries.insert(
key,
Entry {
value: Arc::new(value),
meta,
},
);
}
let old_map: RefCell<Arc<HashMap<String, Entry<T>>>> = RefCell::new(Arc::new(HashMap::new()));
self.inner.rcu(|current_map| {
*old_map.borrow_mut() = Arc::clone(current_map);
let mut result = new_entries.clone();
for (key, entry) in current_map.iter() {
if !result.contains_key(key) && entry.meta.policy == UnloadPolicy::Persistent {
result.insert(key.clone(), entry.clone());
}
}
result
});
let old_map = old_map.into_inner();
#[cfg(feature = "events")]
self.emit_replace_events(&old_map, &new_entries, &provided_keys);
#[cfg(not(feature = "events"))]
{
let _ = (old_map, provided_keys);
}
}
#[cfg(feature = "events")]
fn emit_replace_events(
&self,
old_map: &HashMap<String, Entry<T>>,
new_entries: &HashMap<String, Entry<T>>,
provided_keys: &HashSet<String>,
) {
for (key, new_entry) in new_entries {
if let Some(old_entry) = old_map.get(key) {
if !Arc::ptr_eq(&old_entry.value, &new_entry.value) {
let _ = self.events.send(HoldEvent::Updated {
key: key.clone(),
old: Arc::clone(&old_entry.value),
new: Arc::clone(&new_entry.value),
meta: new_entry.meta.clone(),
});
}
} else {
let _ = self.events.send(HoldEvent::Loaded {
key: key.clone(),
value: Arc::clone(&new_entry.value),
meta: new_entry.meta.clone(),
});
}
}
for (key, old_entry) in old_map.iter() {
if !provided_keys.contains(key) {
if old_entry.meta.policy == UnloadPolicy::Persistent {
let error = HoldError::PersistentRemoval { key: key.clone() };
let _ = self.events.send(HoldEvent::Retained {
key: key.clone(),
error,
});
} else {
let _ = self.events.send(HoldEvent::Removed {
key: key.clone(),
value: Arc::clone(&old_entry.value),
});
}
}
}
}
}