use crate::policy::AccessEvent;
use crate::shared::CacheShared;
use crate::sync::WriteGuard;
use std::hash::{BuildHasher, Hash};
use std::sync::Arc;
pub enum Entry<'a, K: Send, V: Send + Sync, H> {
Occupied(OccupiedEntry<'a, K, V, H>),
Vacant(VacantEntry<'a, K, V, H>),
}
impl<'a, K, V, H> Entry<'a, K, V, H>
where
K: Eq + Hash + Clone + Send,
V: Send + Sync,
H: BuildHasher + Clone,
{
pub fn or_insert(self, default: V, cost: u64) -> Arc<V> {
match self {
Entry::Occupied(o) => o.get(),
Entry::Vacant(v) => v.insert(default, cost),
}
}
pub fn or_insert_with<F>(self, default: F, cost: u64) -> Arc<V>
where
F: FnOnce() -> V,
{
match self {
Entry::Occupied(o) => o.get(),
Entry::Vacant(v) => v.insert(default(), cost),
}
}
pub fn or_default(self, cost: u64) -> Arc<V>
where
V: Default,
{
match self {
Entry::Occupied(o) => o.get(),
Entry::Vacant(v) => v.insert(V::default(), cost),
}
}
}
pub struct OccupiedEntry<'a, K: Send, V: Send, H> {
pub(crate) key: K,
pub(crate) shard_guard:
WriteGuard<'a, std::collections::HashMap<K, Arc<crate::entry::CacheEntry<V>>, H>>,
}
impl<'a, K, V: Send, H> OccupiedEntry<'a, K, V, H>
where
K: std::cmp::Eq + Hash + Send,
H: BuildHasher,
{
pub fn key(&self) -> &K {
&self.key
}
pub fn get(&self) -> Arc<V> {
self.shard_guard.get(&self.key).unwrap().value()
}
}
pub struct VacantEntry<'a, K: Send, V: Send + Sync, H> {
pub(crate) key: K,
pub(crate) shared: &'a Arc<CacheShared<K, V, H>>,
pub(crate) shard_guard:
WriteGuard<'a, std::collections::HashMap<K, Arc<crate::entry::CacheEntry<V>>, H>>,
}
impl<'a, K, V, H> VacantEntry<'a, K, V, H>
where
K: Eq + Hash + Clone + Send,
V: Send + Sync,
H: BuildHasher + Clone,
{
pub fn key(&self) -> &K {
&self.key
}
pub fn insert(mut self, value: V, cost: u64) -> Arc<V> {
let new_cache_entry = Arc::new(crate::entry::CacheEntry::new(
value,
cost,
self.shared.time_to_live,
self.shared.time_to_idle,
));
let value_arc_to_return = new_cache_entry.value();
let key_for_event = self.key.clone();
self.shard_guard.insert(self.key, new_cache_entry);
drop(self.shard_guard);
let shard = self.shared.store.get_shard(&key_for_event);
let _ = shard
.event_buffer_tx
.try_send(AccessEvent::Write(key_for_event, cost));
self
.shared
.metrics
.inserts
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
self
.shared
.metrics
.keys_admitted
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
self
.shared
.metrics
.current_cost
.fetch_add(cost, std::sync::atomic::Ordering::Relaxed);
self
.shared
.metrics
.total_cost_added
.fetch_add(cost, std::sync::atomic::Ordering::Relaxed);
value_arc_to_return
}
pub fn or_insert(self, default: V, cost: u64) -> Arc<V> {
self.insert(default, cost)
}
pub fn or_insert_with<F>(self, default: F, cost: u64) -> Arc<V>
where
F: FnOnce() -> V,
{
self.insert(default(), cost)
}
pub fn or_default(self, cost: u64) -> Arc<V>
where
V: Default,
{
self.insert(V::default(), cost)
}
}