use std::sync::Mutex;
pub(crate) struct StripedLocks {
stripes: Box<[Mutex<()>]>,
hash_shift: u32,
}
impl StripedLocks {
const HASH_MULTIPLIER: u64 = 0x9E3779B97F4A7C15;
pub(crate) fn new() -> Self {
let cpus = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8);
let count = (cpus * 4).next_power_of_two().max(64);
let hash_shift = 64 - count.trailing_zeros();
Self {
stripes: (0..count)
.map(|_| Mutex::new(()))
.collect::<Vec<_>>()
.into_boxed_slice(),
hash_shift,
}
}
#[inline]
fn stripe_index(&self, id: usize) -> usize {
((id as u64).wrapping_mul(Self::HASH_MULTIPLIER) >> self.hash_shift) as usize
}
#[inline]
pub(crate) fn lock(&self, id: usize) -> std::sync::MutexGuard<'_, ()> {
let stripe = self.stripe_index(id);
self.stripes[stripe]
.lock()
.unwrap_or_else(|e| e.into_inner())
}
}