Skip to main content

BackoffState

Struct BackoffState 

Source
pub struct BackoffState<S> { /* private fields */ }
Expand description

A wrapper around a BackoffStrategy to be used in CAS loops when the atomic value must be checked after each reload.

Contrary to BackoffStrategy::backoff_reload, it allows checking for a termination condition and early exiting the loop before performing the backoff.

In order to avoid code duplication with the checks after the reloads, BackoffState::backoff_reload should be called at every iteration of the CAS loop before the CAS. However, to avoid performing a backoff before any CAS failure, BackoffState is initialized as disabled, and enabled after the first backoff_reload call.

§Examples

fn try_update_with_backoff(
    atomic: &AtomicUsize,
    set_order: Ordering,
    fetch_order: Ordering,
    mut f: impl FnMut(usize) -> Option<usize>,
    strategy: impl BackoffStrategy,
) -> Result<usize, usize> {
    let mut backoff = BackoffState::new(strategy);
    let mut current = atomic.load(fetch_order);
    loop {
        // Check the termination condition before backing off.
        let new = f(current).ok_or(current)?;
        // If the value has been reloaded, `new` must be recomputed.
        if backoff.backoff_reload(&mut current, || atomic.load(fetch_order)) {
            continue;
        }
        match atomic.compare_exchange_weak(current, new, set_order, fetch_order) {
            Ok(x) => return Ok(x),
            Err(cur) => current = cur,
        }
    }
}

Implementations§

Source§

impl<S: BackoffStrategy> BackoffState<S>

Source

pub fn new(strategy: S) -> Self

Creates a new BackoffState with the given backoff strategy.

The backoff starts as disabled so the first iteration before any CAS failure doesn’t wait.

Source

pub fn enable(self) -> Self

Starts the backoff in enabled mode.

It is useful when the first CAS iteration is inlined in a hot function, and the complete CAS loop with the backoff is outlined in a cold function, so the backoff must start enabled after a CAS failure.

Source

pub fn backoff_reload<T: PartialEq, F: FnOnce() -> T>( &mut self, current: &mut T, reload: F, ) -> bool

Enables the backoff for the next iteration or perform a backoff if already enabled.

Returns true if the current atomic value has been updated after a reload, in which case the new atomic value should be recomputed before retrying the CAS.

The backoff can be temporarily disabled after a reload triggered by RetryStrategy::Reload in order to execute the CAS with the reloaded value at the next iteration.

Trait Implementations§

Source§

impl<S: Debug> Debug for BackoffState<S>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S: Default> Default for BackoffState<S>

Source§

fn default() -> BackoffState<S>

Returns the “default value” for a type. Read more
Source§

impl<S: BackoffStrategy> From<S> for BackoffState<S>

Source§

fn from(strategy: S) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<S> Freeze for BackoffState<S>
where S: Freeze,

§

impl<S> RefUnwindSafe for BackoffState<S>
where S: RefUnwindSafe,

§

impl<S> Send for BackoffState<S>
where S: Send,

§

impl<S> Sync for BackoffState<S>
where S: Sync,

§

impl<S> Unpin for BackoffState<S>
where S: Unpin,

§

impl<S> UnsafeUnpin for BackoffState<S>
where S: UnsafeUnpin,

§

impl<S> UnwindSafe for BackoffState<S>
where S: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.