arc_swap

Struct ArcSwapAny

source
pub struct ArcSwapAny<T: RefCnt, S: Strategy<T> = DefaultStrategy> { /* private fields */ }
Expand description

An atomic storage for a reference counted smart pointer like Arc or Option<Arc>.

This is a storage where a smart pointer may live. It can be read and written atomically from several threads, but doesn’t act like a pointer itself.

One can be created from an Arc. To get the pointer back, use the load.

§Note

This is the common generic implementation. This allows sharing the same code for storing both Arc and Option<Arc> (and possibly other similar types).

In your code, you most probably want to interact with it through the ArcSwap and ArcSwapOption aliases. However, the methods they share are described here and are applicable to both of them. That’s why the examples here use ArcSwap ‒ but they could as well be written with ArcSwapOption or ArcSwapAny.

§Type parameters

  • T: The smart pointer to be kept inside. This crate provides implementation for Arc<_> and Option<Arc<_>> (Rc too, but that one is not practically useful). But third party could provide implementations of the RefCnt trait and plug in others.
  • S: Chooses the strategy used to protect the data inside. They come with various performance trade offs, the default DefaultStrategy is good rule of thumb for most use cases.

§Examples

let arc = Arc::new(42);
let arc_swap = ArcSwap::from(arc);
assert_eq!(42, **arc_swap.load());
// It can be read multiple times
assert_eq!(42, **arc_swap.load());

// Put a new one in there
let new_arc = Arc::new(0);
assert_eq!(42, *arc_swap.swap(new_arc));
assert_eq!(0, **arc_swap.load());

§Known bugs

Currently, things like ArcSwapAny<Option<Option<Arc<_>>>> (notice the double Option) don’t work properly. A proper solution is being looked into (#81).

Implementations§

source§

impl<T: RefCnt, S: Strategy<T>> ArcSwapAny<T, S>

source

pub fn new(val: T) -> Self
where S: Default,

Constructs a new storage.

source

pub fn with_strategy(val: T, strategy: S) -> Self

Constructs a new storage while customizing the protection strategy.

source

pub fn into_inner(self) -> T

Extracts the value inside.

source

pub fn load_full(&self) -> T

Loads the value.

This makes another copy of the held pointer and returns it, atomically (it is safe even when other thread stores into the same instance at the same time).

The method is lock-free and wait-free, but usually more expensive than load.

source

pub fn load(&self) -> Guard<T, S>

Provides a temporary borrow of the object inside.

This returns a proxy object allowing access to the thing held inside. However, there’s only limited amount of possible cheap proxies in existence for each thread ‒ if more are created, it falls back to equivalent of load_full internally.

This is therefore a good choice to use for eg. searching a data structure or juggling the pointers around a bit, but not as something to store in larger amounts. The rule of thumb is this is suited for local variables on stack, but not in long-living data structures.

§Consistency

In case multiple related operations are to be done on the loaded value, it is generally recommended to call load just once and keep the result over calling it multiple times. First, keeping it is usually faster. But more importantly, the value can change between the calls to load, returning different objects, which could lead to logical inconsistency. Keeping the result makes sure the same object is used.

struct Point {
    x: usize,
    y: usize,
}

fn print_broken(p: &ArcSwap<Point>) {
    // This is broken, because the x and y may come from different points,
    // combining into an invalid point that never existed.
    println!("X: {}", p.load().x);
    // If someone changes the content now, between these two loads, we
    // have a problem
    println!("Y: {}", p.load().y);
}

fn print_correct(p: &ArcSwap<Point>) {
    // Here we take a snapshot of one specific point so both x and y come
    // from the same one.
    let point = p.load();
    println!("X: {}", point.x);
    println!("Y: {}", point.y);
}
source

pub fn store(&self, val: T)

Replaces the value inside this instance.

Further loads will yield the new value. Uses swap internally.

source

pub fn swap(&self, new: T) -> T

Exchanges the value inside this instance.

source

pub fn compare_and_swap<C>(&self, current: C, new: T) -> Guard<T, S>
where C: AsRaw<T::Base>, S: CaS<T>,

Swaps the stored Arc if it equals to current.

If the current value of the ArcSwapAny equals to current, the new is stored inside. If not, nothing happens.

The previous value (no matter if the swap happened or not) is returned. Therefore, if the returned value is equal to current, the swap happened. You want to do a pointer-based comparison to determine it.

In other words, if the caller „guesses“ the value of current correctly, it acts like swap, otherwise it acts like load_full (including the limitations).

The current can be specified as &Arc, Guard, &Guards or as a raw pointer (but not owned Arc). See the AsRaw trait.

source

pub fn rcu<R, F>(&self, f: F) -> T
where F: FnMut(&T) -> R, R: Into<T>, S: CaS<T>,

Read-Copy-Update of the pointer inside.

This is useful in read-heavy situations with several threads that sometimes update the data pointed to. The readers can just repeatedly use load without any locking. The writer uses this method to perform the update.

In case there’s only one thread that does updates or in case the next version is independent of the previous one, simple swap or store is enough. Otherwise, it may be needed to retry the update operation if some other thread made an update in between. This is what this method does.

§Examples

This will not work as expected, because between loading and storing, some other thread might have updated the value.

let cnt = ArcSwap::from_pointee(0);
thread::scope(|scope| {
    for _ in 0..10 {
        scope.spawn(|_| {
           let inner = cnt.load_full();
            // Another thread might have stored some other number than what we have
            // between the load and store.
            cnt.store(Arc::new(*inner + 1));
        });
    }
}).unwrap();
// This will likely fail:
// assert_eq!(10, *cnt.load_full());

This will, but it can call the closure multiple times to retry:

let cnt = ArcSwap::from_pointee(0);
thread::scope(|scope| {
    for _ in 0..10 {
        scope.spawn(|_| cnt.rcu(|inner| **inner + 1));
    }
}).unwrap();
assert_eq!(10, *cnt.load_full());

Due to the retries, you might want to perform all the expensive operations before the rcu. As an example, if there’s a cache of some computations as a map, and the map is cheap to clone but the computations are not, you could do something like this:

fn expensive_computation(x: usize) -> usize {
    x * 2 // Let's pretend multiplication is *really expensive expensive*
}

type Cache = HashMap<usize, usize>;

static CACHE: Lazy<ArcSwap<Cache>> = Lazy::new(|| ArcSwap::default());

fn cached_computation(x: usize) -> usize {
    let cache = CACHE.load();
    if let Some(result) = cache.get(&x) {
        return *result;
    }
    // Not in cache. Compute and store.
    // The expensive computation goes outside, so it is not retried.
    let result = expensive_computation(x);
    CACHE.rcu(|cache| {
        // The cheaper clone of the cache can be retried if need be.
        let mut cache = HashMap::clone(&cache);
        cache.insert(x, result);
        cache
    });
    result
}

assert_eq!(42, cached_computation(21));
assert_eq!(42, cached_computation(21));
§The cost of cloning

Depending on the size of cache above, the cloning might not be as cheap. You can however use persistent data structures ‒ each modification creates a new data structure, but it shares most of the data with the old one (which is usually accomplished by using Arcs inside to share the unchanged values). Something like rpds or im might do what you need.

source

pub fn map<I, R, F>(&self, f: F) -> Map<&Self, I, F>
where F: Fn(&I) -> &R + Clone, Self: Access<I>,

Provides an access to an up to date projection of the carried data.

§Motivation

Sometimes, an application consists of components. Each component has its own configuration structure. The whole configuration contains all the smaller config parts.

For the sake of separation and abstraction, it is not desirable to pass the whole configuration to each of the components. This allows the component to take only access to its own part.

§Lifetimes & flexibility

This method is not the most flexible way, as the returned type borrows into the ArcSwap. To provide access into eg. Arc<ArcSwap<T>>, you can create the Map type directly. See the access module.

§Performance

As the provided function is called on each load from the shared storage, it should generally be cheap. It is expected this will usually be just referencing of a field inside the structure.

§Examples
use std::sync::Arc;

use arc_swap::ArcSwap;
use arc_swap::access::Access;

struct Cfg {
    value: usize,
}

fn print_many_times<V: Access<usize>>(value: V) {
    for _ in 0..25 {
        let value = value.load();
        println!("{}", *value);
    }
}

let shared = ArcSwap::from_pointee(Cfg { value: 0 });
let mapped = shared.map(|c: &Cfg| &c.value);
crossbeam_utils::thread::scope(|s| {
    // Will print some zeroes and some twos
    s.spawn(|_| print_many_times(mapped));
    s.spawn(|_| shared.store(Arc::new(Cfg { value: 2 })));
}).expect("Something panicked in a thread");
source§

impl<T, S: Strategy<Arc<T>>> ArcSwapAny<Arc<T>, S>

source

pub fn from_pointee(val: T) -> Self
where S: Default,

A convenience constructor directly from the pointed-to value.

Direct equivalent for ArcSwap::new(Arc::new(val)).

source§

impl<T, S: Strategy<Option<Arc<T>>>> ArcSwapAny<Option<Arc<T>>, S>

source

pub fn from_pointee<V: Into<Option<T>>>(val: V) -> Self
where S: Default,

A convenience constructor directly from a pointed-to value.

This just allocates the Arc under the hood.

§Examples
use arc_swap::ArcSwapOption;

let empty: ArcSwapOption<usize> = ArcSwapOption::from_pointee(None);
assert!(empty.load().is_none());
let non_empty: ArcSwapOption<usize> = ArcSwapOption::from_pointee(42);
assert_eq!(42, **non_empty.load().as_ref().unwrap());
source

pub fn empty() -> Self
where S: Default,

A convenience constructor for an empty value.

This is equivalent to ArcSwapOption::new(None).

source§

impl<T> ArcSwapAny<Option<Arc<T>>>

source

pub const fn const_empty() -> Self

A const-fn equivalent of empty.

Just like empty, this creates an None-holding ArcSwapOption. The empty is, however, more general ‒ this is available only for the default strategy, while empty is for any Default-constructible strategy (current or future one).

§Examples
static GLOBAL_DATA: ArcSwapOption<usize> = ArcSwapOption::const_empty();

assert!(GLOBAL_DATA.load().is_none());
GLOBAL_DATA.store(Some(Arc::new(42)));
assert_eq!(42, **GLOBAL_DATA.load().as_ref().unwrap());

Trait Implementations§

source§

impl<T, S: Strategy<Arc<T>>> Access<T> for ArcSwapAny<Arc<T>, S>

source§

type Guard = DirectDeref<Arc<T>, S>

A guard object containing the value and keeping it alive. Read more
source§

fn load(&self) -> Self::Guard

The loading method. Read more
source§

impl<T, S: Strategy<Rc<T>>> Access<T> for ArcSwapAny<Rc<T>, S>

source§

type Guard = DirectDeref<Rc<T>, S>

A guard object containing the value and keeping it alive. Read more
source§

fn load(&self) -> Self::Guard

The loading method. Read more
source§

impl<T: RefCnt, S: Strategy<T>> Access<T> for ArcSwapAny<T, S>

source§

type Guard = Guard<T, S>

A guard object containing the value and keeping it alive. Read more
source§

fn load(&self) -> Self::Guard

The loading method. Read more
source§

impl<T, S: Strategy<T>> Debug for ArcSwapAny<T, S>
where T: Debug + RefCnt,

source§

fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult

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

impl<T: RefCnt + Default, S: Default + Strategy<T>> Default for ArcSwapAny<T, S>

source§

fn default() -> Self

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

impl<T, S: Strategy<T>> Display for ArcSwapAny<T, S>
where T: Display + RefCnt,

source§

fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult

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

impl<T: RefCnt, S: Strategy<T>> Drop for ArcSwapAny<T, S>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<T: RefCnt, S: Default + Strategy<T>> From<T> for ArcSwapAny<T, S>

source§

fn from(val: T) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T, S = HybridStrategy<DefaultConfig>> !Freeze for ArcSwapAny<T, S>

§

impl<T, S> RefUnwindSafe for ArcSwapAny<T, S>

§

impl<T, S> Send for ArcSwapAny<T, S>
where S: Send, T: Send,

§

impl<T, S> Sync for ArcSwapAny<T, S>
where S: Sync, T: Sync,

§

impl<T, S> Unpin for ArcSwapAny<T, S>
where S: Unpin, T: Unpin,

§

impl<T, S> UnwindSafe for ArcSwapAny<T, S>

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, A> DynAccess<T> for A
where A: Access<T>, <A as Access<T>>::Guard: 'static,

source§

fn load(&self) -> DynGuard<T>

The equivalent of Access::load.
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> ToString for T
where T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.