use std::sync::Mutex;
use std::sync::MutexGuard;
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use tracing::error;
use tracing::warn;
static POISON_RECOVERY_COUNT: AtomicU64 = AtomicU64::new(0);
fn record_poison_recovery() -> u64 {
POISON_RECOVERY_COUNT.fetch_add(1, Ordering::Relaxed) + 1
}
pub fn rwlock_read_or_recover<T>(lock: &RwLock<T>) -> RwLockReadGuard<'_, T> {
lock.read().unwrap_or_else(|poisoned| {
let count = record_poison_recovery();
error!(
"ERROR: RwLock poisoned (read) - a thread panicked while holding this lock. \
Data may be inconsistent. Attempting recovery."
);
warn!(poison_recovery_count = count, "Poison recovery performed");
poisoned.into_inner()
})
}
pub fn rwlock_write_or_recover<T>(lock: &RwLock<T>) -> RwLockWriteGuard<'_, T> {
lock.write().unwrap_or_else(|poisoned| {
let count = record_poison_recovery();
error!(
"ERROR: RwLock poisoned (write) - a thread panicked while holding this lock. \
Data may be inconsistent. Attempting recovery."
);
warn!(poison_recovery_count = count, "Poison recovery performed");
poisoned.into_inner()
})
}
pub fn mutex_lock_or_recover<T>(lock: &Mutex<T>) -> MutexGuard<'_, T> {
lock.lock().unwrap_or_else(|poisoned| {
let count = record_poison_recovery();
error!(
"ERROR: Mutex poisoned - a thread panicked while holding this lock. \
Data may be inconsistent. Attempting recovery."
);
warn!(poison_recovery_count = count, "Poison recovery performed");
poisoned.into_inner()
})
}