Skip to main content

Crate myelon

Crate myelon 

Source
Expand description

Multiprocess shared-memory transport for inference and other low-latency pipelines.

myelon is the full transport surface built on top of disruptor_mp.

The design goal is straightforward:

  • the raw ring should remain reachable
  • the higher layers should be available when you need them
  • callers should not have to assemble framing, typed transport, and zero-copy access as separate dependencies

myelon therefore re-exports the raw substrate from disruptor_mp and adds framed transport, codec-backed typed transport, typed zero-copy, topology helpers, and transport-layout helpers behind one dependency.

Both myelon and disruptor-mp are valid entry points. Use myelon when you want the higher-level transport layers available; use disruptor-mp directly when you only need the raw substrate. Type identity is preserved across the re-export boundary, so a disruptor_mp::SharedConsumer<E> is the same type as a myelon::SharedConsumer<E>.

§What this crate exposes

NeedLayerType
Fixed-size, Copy event. You own the wire format.0 — rawSharedProducer<E> / SharedConsumer<E> (SHM) or MmapProducer<E> / MmapConsumer<E> (mmap)
Variable-length &[u8] payloads, possibly larger than one ring slot. Need start/end flags + a message id.1 — framedtransport::FramedTransportProducer / transport::FramedTransportConsumer (SHM) or transport::MmapFramedTransportProducer / transport::MmapFramedTransportConsumer (mmap)
Typed message with serialisation (bincode / rkyv / flatbuffers). Owned decode on the consumer side.2 — codectyped_transport::TypedProducer / typed_transport::TypedConsumer + a codec::Codec impl
Same as Layer 2 but consumer reads serialised data in-place — no deserialize allocation.3 — typed zero-copytyped_transport::TypedProducer / typed_transport::TypedConsumer + a codec::ZeroCopyCodec impl

Pick the highest-level surface that matches your data model, then measure before stepping down.

§Choosing a frame size

The framed transport’s frame type is a const generic — callers pick the per-frame payload capacity at compile time:

use myelon::transport::{FixedFrame, AlignedFixedFrame};
type Frame64K = FixedFrame<{ 64 * 1024 - 12 }>;       // 12-byte header
type FrameTiny = FixedFrame<256>;
type Frame4K  = FixedFrame<{ 4 * 1024 - 12 }>;
type ZcFrame  = AlignedFixedFrame<{ 64 * 1024 - 16 }>; // 16-byte header

There is nothing special about 64 KB — that is just the convention perf-bench uses. The trade-off:

Frame sizeEffect
Larger DATA_BYTESBigger ring slot, bigger SHM footprint for the same depth, but messages that fit in one slot avoid fragmentation.
Smaller DATA_BYTESSmaller slot, tighter memory, multi-frame fragmentation kicks in once payload exceeds DATA_BYTES.
Right-sized to dominant payloadSingle-frame messages, lowest overhead, at the cost of flexibility for atypical sizes.

The slot size must be a compile-time constant so the ring layout is known. To support a runtime-chosen size, instantiate one transport per size class. perf-bench’s nofrag mode is a worked example of this pattern.

§Two senses of zero-copy

Two different things in this stack get called “zero-copy”, and they’re not the same:

SenseWhereHow
Memory-level zero-copyLayer 0 already provides this.try_consume_next_leased() returns &E straight into the ring slot. No allocation, no copy. Use this for fixed-size Copy + repr(C) events.
Typed-format zero-copyLayer 3.The bytes on the wire are already a serialised graph (rkyv Archived<T> or a flatbuffers root table); the consumer reads fields in-place via codec::ZeroCopyCodec::access.

There is no separate “raw + typed zero-copy” layer. If your event is fixed-size and Copy + repr(C), just put the struct in the slot — Layer 0 is already memory-zero-copy and outperforms an archived blob. If you want serialisation flexibility, you also want framing. The four-layer picture covers both senses without overlap.

§Cross-cutting concerns

These wrap across layers — pick them by what your system needs, not by what your wire format needs.

ConcernTypePurpose
Coordinationproducer::CoordinationModeWhen does the producer consider its peers attached?
Discoverybuilder methods on SharedDisruptorBuilderProducer locates consumers by explicit ID or by prefix.
LivenessRequiredConsumerLivenessConfig, RequiredConsumerFailureAction (see below)A stalled required consumer becomes a failure or alert, not silent backpressure.
Topologyinference::FixedTopology, inference::WorkerCountPre-baked one-scheduler / N-worker shape with discovery + rendezvous.
Layouttransport::MyelonTransportLayout, transport::MyelonTransportConfig, transport::RunnerMyelonTransportConfigmacOS-safe SHM segment names for one-engine / N-runner sessions.
Observabilityobservability (re-export of disruptor_mp::observability)RFC-0040 hot-path counters file.

§Required-consumer liveness

Out of the box, the base model is strict broadcast — the slowest consumer gates capacity. A stalled or crashed required consumer therefore backpressures the producer indefinitely. The optional liveness layer turns that silent stall into a producer-observable, time-bounded event.

It is opt-in through a parallel *_managed publish surface. Existing unmanaged calls (publish, try_publish, publish_batch) keep their original semantics; nothing changes for callers that don’t opt in.

Available on every layer:

Layer / backendTypeMethods
0, SHMSharedProducer<E>enable_required_consumer_liveness, publish_managed, publish_batch_managed
0, mmapMmapProducer<E>same
1, SHMtransport::FramedTransportProducerenable_required_consumer_liveness, publish_managed
1, mmaptransport::MmapFramedTransportProducersame
2/3, SHMtyped_transport::TypedProducerenable_required_consumer_liveness, publish_managed
2/3, mmaptyped_transport::MmapTypedProducersame

Failure surface (returned from publish_managed):

CaseOutcome
Required consumer doesn’t appear within startup_wait_timeout.RequiredConsumerError::StartupTimeout
Required consumer stalls past progress_timeout while gating the producer.One stderr alert + optional RequiredConsumerAlertHook callback.
Same consumer ID rejoins before shutdown_grace_period expires.Producer recovers, alert state clears, publishing resumes.
Stall persists past shutdown_grace_period.RequiredConsumerError::GracefulShutdownTriggered

The liveness check is cold-path only — it runs only while the producer is blocked on a gating required consumer. Steady-state publish cost is unchanged. There is no consumer-side heartbeat; progress is observed from the cursor data the producer already needs for gating.

By design the liveness layer does not add dead-consumer eviction, quorum modes, or degraded broadcast. The topology stays strict-broadcast.

§Feature flags

FeatureLayer / surfaceWhat it enables
(default)Layers 0, 1; Layer 2 with bincode onlyRaw + framed transport, plus the bincode codec.
rkyvLayer 2/3 with rkyvRe-exports rkyv and the rkyv codec wrappers (incl. codec::ZeroCopyCodec).
flatbuffersLayer 2/3 with flatbuffersRe-exports flatbuffers and the flatbuffers codec wrappers.
dsttests onlyForwards to disruptor_mp/dst for deterministic-simulation hooks.

§Quick start

use myelon::{
    attach_shared_consumer, build_shared_single_producer,
};
use myelon::producer::CoordinationMode;
use disruptor_mp::portable_shm_segment_name;
let segment = portable_shm_segment_name("demo");
let mut producer = build_shared_single_producer::<Event>(&segment, 4096)
    .discover_consumer_with_prefix(1, "cp")
    .with_coordination(CoordinationMode::Immediate)
    .build_producer(Event::default)
    .expect("build producer");
producer.publish(|slot| slot.sequence = 1);

See the crate README for fuller Layer 1 / Layer 2 / Layer 3 examples.

Re-exports§

pub use inference::FixedTopology;
pub use inference::InferenceTopologyError;
pub use inference::InferenceTopologyResult;
pub use inference::WorkerCount;
pub use transport::compact_session_tag;
pub use transport::coordination_cursor_name;
pub use transport::ensure_coordination_cursor;
pub use transport::frame_flags;
pub use transport::is_last_frame;
pub use transport::is_single_frame;
pub use transport::publish_framed_payload;
pub use transport::recv_framed_message;
pub use transport::validate_segment_name;
pub use transport::AlignedFixedFrame;
pub use transport::FrameMeta;
pub use transport::MmapFramedTransportConsumer;
pub use transport::MmapFramedTransportProducer;
pub use transport::MyelonTransportConfig;
pub use transport::MyelonTransportLayout;
pub use transport::MyelonWaitStrategy;
pub use transport::RunnerMyelonTransportConfig;
pub use transport::TransportError;
pub use transport::TransportResult;
pub use transport::DEFAULT_MYELON_RESPONSE_DEPTH;
pub use transport::DEFAULT_MYELON_RPC_DEPTH;
pub use transport::DEFAULT_TRANSPORT_PREFIX;
pub use transport::SEGMENT_NAME_LIMIT_MACOS;
pub use codec::Codec;
pub use codec::CodecError;
pub use typed_transport::MmapTypedConsumer;
pub use typed_transport::MmapTypedProducer;
pub use typed_transport::TypedConsumer;
pub use typed_transport::TypedProducer;
pub use typed_transport::TypedPublishError;
pub use rkyv;
pub use flatbuffers;

Modules§

backend
Backend façade namespace for shared-memory implementation.
codec
Zero-copy message codec for the Myelon transport.
consumer
Consumer façade namespace for shared-memory consumer behavior.
inference
Fixed-topology inference helpers over the curated disruptor-mp façade.
lock_free
Lock-free coordination façade types.
observability
Re-export of disruptor_mp::observability for downstream users that want to attach Aeron-style hot-path counters without taking a direct dependency on disruptor-mp. RFC 0040.
prelude
Convenience re-exports for downstream code that wants the typical transport, codec, and observability surface in one use line.
producer
Producer façade namespace for coordinated construction and policy.
shared_memory
Shared-memory top level façade types.
transport
Portable transport helpers for inference-fabric integrations.
typed_transport
Typed transport wrappers that integrate Codec with the raw FramedTransportProducer / FramedTransportConsumer.

Structs§

AutoConsumer
Automatic consumer that runs in a background thread.
MmapConsumer
Consumer for the mmap transport.
MmapProducer
Producer for the mmap transport.
MmapTransportLayout
Stable file layout for one mmap-backed disruptor transport instance.
RequiredConsumerAlert
Producer-side alert emitted when a required consumer stops advancing while gating progress.
RequiredConsumerLivenessConfig
Producer-side liveness policy for a required consumer set.
RingBufferFull
Error indicating that the ring buffer is full.
SharedConsumer
Consumer for multi-process disruptor with broadcast semantics Each consumer maintains its own sequence and sees all events
SharedDisruptorBuilder
Builder for creating multi-process disruptors.
SharedProducer
Multi-process producer for publishing events to shared memory ring buffer.

Enums§

AutoWaitStrategy
Wait strategy for automatic event handlers
CoordinationMode
Coordination mode for multiprocess producer startup
MultiProcessError
Errors that can occur during multi-process setup
RequiredConsumerError
Producer-visible failure when required-consumer liveness cannot be maintained.
RequiredConsumerFailureAction
Action to take when a required consumer stops making progress.

Constants§

DEFAULT_MAX_CONSUMERS
Default maximum number of consumers that can be registered with a single shared ring buffer.
PORTABLE_SHM_SEGMENT_NAME_MAX_LEN
Conservative shared-memory segment-name budget that stays portable on macOS.

Functions§

attach_shared_consumer
Attach to an existing shared disruptor as a consumer
build_shared_single_producer
Create a shared single producer for multi-process communication
default_block_strategy_duration
Return the configured backoff used by AutoWaitStrategy::Block.
default_consume_sleep_duration
Return the configured sleep used by consume_next_with_sleep and similar helpers.
default_discovery_poll_duration
Return the configured poll interval used by discovery/startup coordination loops.
perform_default_block_wait
Apply the configured AutoWaitStrategy::Block wait policy.
perform_default_consume_sleep_wait
Apply the configured consumer sleep wait policy.
perform_default_discovery_poll_wait
Apply the configured discovery/startup polling wait policy.
perform_sleep_wait
Apply the explicit AutoWaitStrategy::Sleep(duration) wait policy.
portable_shm_segment_name
Generate a shared-memory segment name that fits the portable macOS-safe budget.

Type Aliases§

MultiProcessResult
Result type for multi-process operations
RequiredConsumerAlertHook
Optional embedding hook invoked when producer-side stall alerting fires.
Sequence
The type for Sequence numbers in the Ring Buffer (i64).