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§
Sourcepub fn create(
path: impl AsRef<Path>,
capacity: usize,
) -> Result<Self, DequeError>
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.
Sourcepub fn open_as_thief(path: impl AsRef<Path>) -> Result<Self, DequeError>
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.
Sourcepub fn approx_len(&self) -> usize
pub fn approx_len(&self) -> usize
Approximate current length. Not authoritative under concurrent steal / push; useful for heuristics and observers.
Sourcepub fn push(&self, value: &T) -> Result<(), DequeError>
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.
Sourcepub fn push_batch_with<F>(&self, n: usize, fill: F) -> Result<(), DequeError>
pub fn push_batch_with<F>(&self, n: usize, fill: F) -> Result<(), DequeError>
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.
Sourcepub fn push_batch(&self, values: &[T]) -> Result<(), DequeError>
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.
Sourcepub fn pop(&self) -> Option<T>
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.
Sourcepub fn steal(&self) -> Option<T>
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.