moka/notification/
notifier.rs
1use std::sync::{
2 atomic::{AtomicBool, Ordering},
3 Arc,
4};
5
6use crate::notification::{EvictionListener, RemovalCause};
7
8pub(crate) struct RemovalNotifier<K, V> {
9 listener: EvictionListener<K, V>,
10 is_enabled: AtomicBool,
11 #[cfg(feature = "logging")]
12 cache_name: Option<String>,
13}
14
15impl<K, V> RemovalNotifier<K, V> {
16 pub(crate) fn new(listener: EvictionListener<K, V>, _cache_name: Option<String>) -> Self {
17 Self {
18 listener,
19 is_enabled: AtomicBool::new(true),
20 #[cfg(feature = "logging")]
21 cache_name: _cache_name,
22 }
23 }
24
25 pub(crate) fn notify(&self, key: Arc<K>, value: V, cause: RemovalCause) {
26 use std::panic::{catch_unwind, AssertUnwindSafe};
27
28 if !self.is_enabled.load(Ordering::Acquire) {
29 return;
30 }
31
32 let listener_clo = || (self.listener)(key, value, cause);
33
34 let result = catch_unwind(AssertUnwindSafe(listener_clo));
37 if let Err(_payload) = result {
38 self.is_enabled.store(false, Ordering::Release);
39 #[cfg(feature = "logging")]
40 log_panic(&*_payload, self.cache_name.as_deref());
41 }
42 }
43}
44
45#[cfg(feature = "logging")]
46fn log_panic(payload: &(dyn std::any::Any + Send + 'static), cache_name: Option<&str>) {
47 let message: Option<std::borrow::Cow<'_, str>> =
52 (payload.downcast_ref::<&str>().map(|s| (*s).into()))
53 .or_else(|| payload.downcast_ref::<String>().map(Into::into));
54
55 let cn = cache_name
56 .map(|name| format!("[{name}] "))
57 .unwrap_or_default();
58
59 if let Some(m) = message {
60 log::error!("{cn}Disabled the eviction listener because it panicked at '{m}'");
61 } else {
62 log::error!("{cn}Disabled the eviction listener because it panicked");
63 }
64}