minerva 0.2.0

Causal ordering for distributed systems
use super::jitter::jitter_spins;
use super::{Backoff, spin};

/// A constant-intensity backoff: the same spin count every attempt, plus optional
/// jitter.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConstantBackoff {
    spins: u32,
    #[cfg(feature = "rand")]
    jitter: Option<u32>, // max extra spins
    #[cfg(not(feature = "rand"))]
    jitter: Option<(u64, u32)>, // (LCG seed, max extra spins)
}

impl ConstantBackoff {
    #[cfg(feature = "rand")]
    /// A backoff that spins `spins` times per attempt, plus a random extra
    /// count in `[0, jitter)` (the thread RNG supplies the entropy).
    ///
    /// With the `rand` feature off, this signature takes `Option<(seed, max)>`
    /// instead; see [`BackoffStrategy`](super::BackoffStrategy) for the
    /// feature-unification hazard.
    ///
    /// The spin count is a relative contention knob, not a wall-clock duration: a
    /// clockless core cannot honor real time, so backoff is measured in spin-loop
    /// iterations.
    #[must_use]
    pub const fn new(spins: u32, jitter: Option<u32>) -> Self {
        Self { spins, jitter }
    }

    #[cfg(not(feature = "rand"))]
    /// A backoff that spins `spins` times per attempt, plus optional jitter.
    ///
    /// `jitter` is a `(seed, max)` pair: a seed for the in-crate LCG and a
    /// derived extra count in `[0, max)`, de-correlating threads that would
    /// otherwise retry in lock-step. With the `rand` feature on, this
    /// signature takes `Option<u32>` instead; see
    /// [`BackoffStrategy`](super::BackoffStrategy) for the
    /// feature-unification hazard.
    /// The spin count is a relative contention knob, not a wall-clock duration; a
    /// clockless core cannot honor real time.
    #[must_use]
    pub const fn new(spins: u32, jitter: Option<(u64, u32)>) -> Self {
        Self { spins, jitter }
    }
}

impl Backoff for ConstantBackoff {
    fn backoff(&self, attempt: u32) {
        spin(
            self.spins
                .saturating_add(jitter_spins(self.jitter, attempt)),
        );
    }
}