pub struct AtomicBucket<T> { /* private fields */ }
Available on crate feature handles only.
Expand description

A lock-free bucket with snapshot capabilities.

This bucket is implemented as a singly-linked list of blocks, where each block is a small buffer that can hold a handful of elements. There is no limit to how many elements can be in the bucket at a time. Blocks are dynamically allocated as elements are pushed into the bucket.

Unlike a queue, buckets cannot be drained element by element: callers must iterate the whole structure. Reading the bucket happens in a quasi-reverse fashion, to allow writers to make forward progress without affecting the iteration of the previously written values.

For example, in a scenario where an internal block can hold 4 elements, and the caller has written 10 elements to the bucket, you would expect to see the values in this order when iterating:

[6 7 8 9] [2 3 4 5] [0 1]

Block sizes are dependent on the target architecture, where each block can hold N items, and N is the number of bits in the target architecture’s pointer width.

Implementations§

source§

impl<T> AtomicBucket<T>

source

pub fn new() -> Self

Creates a new, empty bucket.

source

pub fn is_empty(&self) -> bool

Checks whether or not this bucket is empty.

source

pub fn push(&self, value: T)

Pushes an element into the bucket.

source

pub fn data(&self) -> Vec<T>
where T: Clone,

Collects all of the elements written to the bucket.

This operation can be slow as it involves allocating enough space to hold all of the elements within the bucket. Consider data_with to incrementally iterate the internal blocks within the bucket.

Elements are in partial reverse order: blocks are iterated in reverse order, but the elements within them will appear in their original order.

source

pub fn data_with<F>(&self, f: F)
where F: FnMut(&[T]),

Iterates all of the elements written to the bucket, invoking f for each block.

Elements are in partial reverse order: blocks are iterated in reverse order, but the elements within them will appear in their original order.

source

pub fn clear(&self)

Clears the bucket.

Deallocation of the internal blocks happens only when all readers have finished, and so will not necessarily occur during or immediately preceding this method.

§Note

This method will not affect reads that are already in progress.

source

pub fn clear_with<F>(&self, f: F)
where F: FnMut(&[T]),

Clears the bucket, invoking f for every block that will be cleared.

Deallocation of the internal blocks happens only when all readers have finished, and so will not necessarily occur during or immediately preceding this method.

This method is useful for accumulating values and then observing them, in a way that allows the caller to avoid visiting the same values again the next time.

This method allows a pattern of observing values before they’re cleared, with a clear demarcation. A similar pattern used in the wild would be to have some data structure, like a vector, which is continuously filled, and then eventually swapped out with a new, empty vector, allowing the caller to read all of the old values while new values are being written, over and over again.

§Note

This method will not affect reads that are already in progress.

Trait Implementations§

source§

impl<T: Debug> Debug for AtomicBucket<T>

source§

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

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

impl<T> Default for AtomicBucket<T>

source§

fn default() -> Self

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

impl HistogramFn for AtomicBucket<f64>

source§

fn record(&self, value: f64)

Records a value into the histogram.

Auto Trait Implementations§

§

impl<T> !Freeze for AtomicBucket<T>

§

impl<T> !RefUnwindSafe for AtomicBucket<T>

§

impl<T> Send for AtomicBucket<T>
where T: Sync + Send,

§

impl<T> Sync for AtomicBucket<T>
where T: Sync + Send,

§

impl<T> Unpin for AtomicBucket<T>

§

impl<T> !UnwindSafe for AtomicBucket<T>

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> Pointable for T

source§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

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

§

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>,

§

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.