diff --git a/src/lib.rs b/src/lib.rs index 7840608..433d0f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,7 +196,43 @@ pub trait Lifecycle { fn before_evict(&self, state: &mut Self::RequestState, key: &Key, val: &mut Val) {} /// Called when an item is evicted. - fn on_evict(&self, state: &mut Self::RequestState, key: Key, val: Val); + /// + /// To distinguish evictions from the hot vs cold queues, override + /// [`Lifecycle::on_evict_hot`] and/or [`Lifecycle::on_evict_cold`] instead; + /// they default to delegating here. + /// + /// If none of `on_evict`, `on_evict_hot`, or `on_evict_cold` is overridden, + /// eviction notifications are silently dropped. + /// + /// Note: items that are rejected without ever being admitted to the cache + /// (oversized inserts and oversized placeholder values) are routed through + /// [`Lifecycle::on_evict_cold`], which by default reaches this method. + #[allow(unused_variables)] + #[inline] + fn on_evict(&self, state: &mut Self::RequestState, key: Key, val: Val) {} + + /// Called when an item is evicted from the cold queue. + /// + /// By default delegates to [`Lifecycle::on_evict`]. + /// + /// Note: items that are rejected without ever being admitted to the cache + /// (oversized inserts and oversized placeholder values) are also reported + /// via this method. + #[inline] + fn on_evict_cold(&self, state: &mut Self::RequestState, key: Key, val: Val) { + self.on_evict(state, key, val) + } + + /// Called when an item is evicted from the hot queue. + /// + /// By default delegates to [`Lifecycle::on_evict`]. + /// + /// Note: rejected (never-admitted) items are reported via + /// [`Lifecycle::on_evict_cold`], not this method. + #[inline] + fn on_evict_hot(&self, state: &mut Self::RequestState, key: Key, val: Val) { + self.on_evict(state, key, val) + } /// Called after a request finishes, e.g.: insert, replace. /// diff --git a/src/shard.rs b/src/shard.rs index ec40b94..bf01c02 100644 --- a/src/shard.rs +++ b/src/shard.rs @@ -783,7 +783,8 @@ impl< if self.num_non_resident > self.capacity_non_resident { self.advance_ghost(); } - self.lifecycle.on_evict(lcs, evicted.key, evicted.value); + self.lifecycle + .on_evict_cold(lcs, evicted.key, evicted.value); return true; } } @@ -835,7 +836,7 @@ impl< unsafe { core::hint::unreachable_unchecked() }; }; self.hot_head = next; - self.lifecycle.on_evict(lcs, evicted.key, evicted.value); + self.lifecycle.on_evict_hot(lcs, evicted.key, evicted.value); self.map_remove(hash, idx); } return true; @@ -920,7 +921,15 @@ impl< } else if evicted_weight != 0 && weight == 0 { *list_head = self.entries.unlink(idx); } - self.lifecycle.on_evict(lcs, evicted.key, evicted.value); + match enter_state { + ResidentState::Hot => { + self.lifecycle.on_evict_hot(lcs, evicted.key, evicted.value) + } + ResidentState::Cold => { + self.lifecycle + .on_evict_cold(lcs, evicted.key, evicted.value) + } + } } Entry::Ghost(_) => { self.weight_hot += weight; @@ -1052,7 +1061,7 @@ impl< ) -> Result<(), Val> { self.entries.remove(placeholder.idx()); self.map_remove(placeholder.hash(), placeholder.idx()); - self.lifecycle.on_evict(lcs, key, value); + self.lifecycle.on_evict_cold(lcs, key, value); Ok(()) } @@ -1120,15 +1129,19 @@ impl< strategy: InsertStrategy, ) -> Result<(), (Key, Val)> { // Make sure to remove any existing entry - if let Some((idx, _)) = self.search_resident(hash, &key) { + if let Some((idx, resident)) = self.search_resident(hash, &key) { + let prev_state = resident.state; if let Some((ek, ev)) = self.remove_internal(hash, idx) { - self.lifecycle.on_evict(lcs, ek, ev); + match prev_state { + ResidentState::Hot => self.lifecycle.on_evict_hot(lcs, ek, ev), + ResidentState::Cold => self.lifecycle.on_evict_cold(lcs, ek, ev), + } } } if matches!(strategy, InsertStrategy::Replace { .. }) { return Err((key, value)); } - self.lifecycle.on_evict(lcs, key, value); + self.lifecycle.on_evict_cold(lcs, key, value); Ok(()) } diff --git a/src/unsync.rs b/src/unsync.rs index 66ee954..ae7f1d5 100644 --- a/src/unsync.rs +++ b/src/unsync.rs @@ -443,9 +443,6 @@ impl Lifecycle for DefaultLifecycle { #[inline] fn begin_request(&self) -> Self::RequestState {} - - #[inline] - fn on_evict(&self, _state: &mut Self::RequestState, _key: Key, _val: Val) {} } #[derive(Debug, Clone)]