Skip to main content

SharedDeque

Struct SharedDeque 

Source
pub struct SharedDeque<T: Marshal> { /* private fields */ }
Expand description

Chase-Lev work-stealing deque backed by a memory-mapped file.

See the module docs for the protocol description and citation. Drop semantics: dropping the handle unmaps the file but does NOT delete it (in keeping with the rest of subetha-cxc’s MMF-backed primitives).

Implementations§

Source§

impl<T: Marshal> SharedDeque<T>

Source

pub fn create( path: impl AsRef<Path>, capacity: usize, ) -> Result<Self, DequeError>

Create a new MMF-backed deque at path with the given capacity. capacity must be a non-zero power of two.

The calling process is recorded as the “owner” in the header for informational purposes; the protocol does not enforce single-owner discipline at runtime - that is a contract the caller’s scheduler is responsible for.

Source

pub fn open_as_thief(path: impl AsRef<Path>) -> Result<Self, DequeError>

Open an existing MMF-backed deque created by another handle.

The caller asserts the role of “thief” - the same protocol works for any number of thief handles open at once, in any number of processes. The header’s slot_bytes field is verified against T::PAYLOAD_BYTES; opening a deque whose slot width does not match T returns DequeError::SlotBytesMismatch.

Source

pub fn capacity(&self) -> usize

Capacity (power of two).

Source

pub fn approx_len(&self) -> usize

Approximate current length. Not authoritative under concurrent steal / push; useful for heuristics and observers.

Source

pub fn push(&self, value: &T) -> Result<(), DequeError>

Owner side: push a value onto the bottom of the deque.

This is the only operation safe to call from the owner thread alone; calling it concurrently from multiple threads breaks the Chase-Lev protocol. The fast path is one Relaxed load on bottom, one Acquire load on top, the marshal, a Release fence, and one Relaxed store on bottom. No CAS, no mutex.

Source

pub fn push_batch_with<F>(&self, n: usize, fill: F) -> Result<(), DequeError>
where F: FnMut(usize, &mut [u8]),

Owner-side batched push via a per-slot fill closure. Reserves n contiguous slots under ONE top.load(Acquire), then calls fill(i, slot_bytes) for each slot, then ONE Release fence and ONE bottom.store(Relaxed) publishes all n slots atomically from the thieves’ perspective.

The closure writes directly into the slot’s raw bytes, avoiding any intermediate T buffer. This is the path caller-defined fat-slot types take when they want to bypass the Marshal indirection on the hot path. Returns Err(Full) if the batch would overflow capacity at the current top snapshot.

Source

pub fn push_batch(&self, values: &[T]) -> Result<(), DequeError>

Owner-side batched push. Amortizes ONE top.load(Acquire), ONE Release fence, and ONE bottom.store(Relaxed) across the whole batch instead of paying them per item. Critical for producer-fast workloads where the per-item top load goes cross-core to the thief and dominates per-push cost.

Returns Err(Full) (and writes no slots) if the batch would overflow capacity at the current top snapshot.

Source

pub fn pop(&self) -> Option<T>

Owner side: pop a value off the bottom of the deque.

Fast path (no contention with thieves) is a single Relaxed load + Relaxed store on bottom, a SeqCst fence, and a Relaxed load on top. Only the contended case - one item left and a thief is trying to take it - falls back to a CAS on top to disambiguate.

Source

pub fn steal(&self) -> Option<T>

Thief side: steal a value off the top of the deque.

Any number of threads or processes can call this concurrently with each other and with the owner’s pop. Each call costs one Acquire load on top, a SeqCst fence, one Acquire load on bottom, a slot read, and one CAS on top. The slot read happens before the CAS so a CAS-loss discards a possibly-stale value safely.

Source

pub fn flush(&self) -> Result<()>

Force the mapped region to be written back to disk. Useful for the disk-persistent deployment mode.

Trait Implementations§

Source§

impl MessageTransport for SharedDeque<PassSlot>

Source§

fn try_push(&self, payload: &[u8]) -> Result<(), TransportError>

Push a payload of length <= PAYLOAD_BYTES. Returns Err(Full) if the transport is at capacity.
Source§

fn try_pop(&self, out: &mut [u8]) -> Result<usize, TransportError>

Pop a payload into out (which must be >= PAYLOAD_BYTES long). Returns the byte count written on success, or Err(Empty) if there is nothing to take.
Source§

impl<T: Marshal + Send> Send for SharedDeque<T>

Source§

impl<T: Marshal + Send> Sync for SharedDeque<T>

Auto Trait Implementations§

§

impl<T> Freeze for SharedDeque<T>

§

impl<T> RefUnwindSafe for SharedDeque<T>
where T: RefUnwindSafe,

§

impl<T> Unpin for SharedDeque<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for SharedDeque<T>

§

impl<T> UnwindSafe for SharedDeque<T>
where T: 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 = 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.