armdb 0.12.0

sharded bitcask key-value storage optimized for NVMe
Documentation
#[cfg(feature = "loom")]
pub(crate) use loom::sync::{Condvar, Mutex, MutexGuard};

#[cfg(all(feature = "parking_lot", not(feature = "loom")))]
pub(crate) use parking_lot::{Condvar, Mutex, MutexGuard};

#[cfg(not(any(feature = "parking_lot", feature = "loom")))]
pub(crate) use std::sync::{Condvar, Mutex, MutexGuard};

#[cfg(feature = "loom")]
#[inline(always)]
pub(crate) fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
    mutex.lock().expect("loom mutex poisoned")
}

#[cfg(all(feature = "parking_lot", not(feature = "loom")))]
#[inline(always)]
pub(crate) fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
    mutex.lock()
}

#[cfg(not(any(feature = "parking_lot", feature = "loom")))]
#[inline(always)]
pub(crate) fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
    mutex.lock().expect("mutex poisoned")
}

/// Try to take `mutex` without blocking.
///
/// Normalises the three backends onto `Option`: `parking_lot` already returns
/// one, while `std` and `loom` return a `TryLockResult` whose error covers both
/// "held" and "poisoned". Poisoned collapses to `None` here — a poisoned mutex
/// means some other thread already panicked while holding it, so "cannot take
/// it" is the honest answer, and [`lock`] panics on that state anyway.
///
/// Only tests probe a lock without blocking today, hence `#[cfg(test)]`.
#[cfg(all(test, feature = "parking_lot", not(feature = "loom")))]
#[inline(always)]
pub(crate) fn try_lock<T>(mutex: &Mutex<T>) -> Option<MutexGuard<'_, T>> {
    mutex.try_lock()
}

#[cfg(all(test, not(all(feature = "parking_lot", not(feature = "loom")))))]
#[inline(always)]
pub(crate) fn try_lock<T>(mutex: &Mutex<T>) -> Option<MutexGuard<'_, T>> {
    mutex.try_lock().ok()
}

#[cfg(all(feature = "parking_lot", not(feature = "loom")))]
#[inline(always)]
pub(crate) fn cv_wait<'a, T>(cv: &Condvar, mut guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
    cv.wait(&mut guard);
    guard
}

#[cfg(not(all(feature = "parking_lot", not(feature = "loom"))))]
#[inline(always)]
pub(crate) fn cv_wait<'a, T>(cv: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
    cv.wait(guard).expect("mutex poisoned")
}

/// Wait on `cv` for at most `timeout`, returning the reacquired guard.
///
/// `mutex` must be the one `guard` came from; it is only used under `loom`,
/// whose `Condvar` has no timed wait — there the guard is dropped, the thread
/// yields, and the lock is retaken. That is a spurious wakeup, which every
/// caller of a condition variable must already tolerate.
#[cfg(all(feature = "parking_lot", not(feature = "loom")))]
#[inline(always)]
pub(crate) fn cv_wait_timeout<'a, T>(
    cv: &Condvar,
    _mutex: &'a Mutex<T>,
    mut guard: MutexGuard<'a, T>,
    timeout: std::time::Duration,
) -> MutexGuard<'a, T> {
    cv.wait_for(&mut guard, timeout);
    guard
}

#[cfg(feature = "loom")]
#[inline(always)]
pub(crate) fn cv_wait_timeout<'a, T>(
    _cv: &Condvar,
    mutex: &'a Mutex<T>,
    guard: MutexGuard<'a, T>,
    _timeout: std::time::Duration,
) -> MutexGuard<'a, T> {
    drop(guard);
    loom::thread::yield_now();
    lock(mutex)
}

#[cfg(not(any(feature = "parking_lot", feature = "loom")))]
#[inline(always)]
pub(crate) fn cv_wait_timeout<'a, T>(
    cv: &Condvar,
    _mutex: &'a Mutex<T>,
    guard: MutexGuard<'a, T>,
    timeout: std::time::Duration,
) -> MutexGuard<'a, T> {
    cv.wait_timeout(guard, timeout).expect("mutex poisoned").0
}