Skip to content
Role Pair Selection

Role-pair selection

The fastest way to pick a SubEtha primitive: find the row whose role pair matches your shape, take the type, move on. The shape - who-talks-to-who - is what determines the primitive. Strategy adaptation is a secondary axis the sidecar handles via the AdaptiveIpc<T> umbrella, which auto-picks among the specialised primitives below based on declarative workload hints.

Cross-process MMF primitives

Use these when the two ends are in different address spaces, or when one end is “the same process tomorrow after a restart”. The data lives in a memory-mapped file; the kernel page-aliases the mapping between participants and there is no kernel on the data path after construction.

Role pairPrimitive
producer + consumer (lock-free MPMC)SharedRing
single-producer + N consumers (fan-out)SharedBroadcastRing
LIFO stackSharedTreiberStack
shared mutable cellSharedCell
one-shot initSharedOnceCell
atomic wordSharedAtomicU32, SharedAtomicU64, SharedAtomicBool
key/value lookupSharedHashMap
LRU cache (bounded, eviction)SharedLRUCache
mutual exclusion (reader/writer)SharedRWLock
counting semaphoreSharedSemaphore
rate limit (token bucket)SharedRateLimiter
logical clock (Lamport / hybrid)SharedFenceClock

Several primitives sit on the same role-pair shape but tune for a specific data layout:

TypeSame role-pair asSpecialisation
SharedBTreeMapSharedHashMapordered keys, range queries
SharedLinkedListSharedTreiberStackdoubly linked, both-end ops
SharedVecSharedRingindexed array, random access
SharedRegion(allocator role pair)sub-allocator inside the MMF

Sketches and probabilistic structures - SharedBloomFilter, SharedCountMinSketch, SharedHyperLogLog, SharedReservoirSampler, SharedHistogram - share the “insert + query” role pair of SharedHashMap but trade exactness for fixed-size footprint.

Work-stealing deques (producer + consumer family)

Several deque variants exist because the workload shape inside “producer + consumer” splits further: batched producers want one shape, work-stealing thieves want another, broadcast fan-out wants a third.

VariantShape that fits
SharedDequeChase-Lev baseline (owner-pop, thief-steal)
SharedDequeKhlKHL - work stealing with per-slot publication radius
SharedDequeKhpdKHPD - publication-line batched fan-out
SharedDequeLohLOH - LIFO cache + LCRQ steal slow path
SharedDequeUrdURD - per-thief mailbox; explicit consumer set
SharedDequeFclFCL - flat combining for high contention

AutoIpc::build_work_steal_queue() with declarative hints (.batch_size, .consumers, .idle_wait) picks among these without the caller naming a variant.

Coordination primitives

The shapes here are not the canonical reader/writer or producer/consumer; they coordinate liveness, ownership, or fan-out across the participants.

Role pairPrimitive
liveness signal across processesHeartbeatTable, SharedLeaderElection
owner of a resource + lease holdersOwnerLease
epoch barrier (all participants synchronise)EpochBarrier
failover (work reassignment on dead peer)FailoverWatchdog
priority fan-outPriorityFanout
event log (emit + drain + fold)EventStateLog
version chain (append-only history)SharedVersionedChain
time-keyed slot tileSharedTimePointTile
topology mapping (fan-in / fan-out routing)SharedTopologyMap
named handle table (transient identifiers)SharedHandleTable
dependency graph (nodes + edges)SharedGraph
async pointer (deferred resolution)SharedAsyncPointer

What to do once you have picked one

  • For a direct cross-process primitive: open or create the MMF via create(path, capacity) or open(path, capacity), then call the primitive’s regular methods. See the cross-process tutorial .
  • For automatic primitive selection: use AutoIpc::new(path) and declare workload hints; the builder picks the best primitive among the table above. See AdaptiveIpc<T> .
  • For a custom policy: implement the Policy trait, build an instance whose make_policy returns your impl, and let the sidecar consult it on each scan. See Write a custom Policy .

See also