Skip to main content

melin_server_runtime/
lib.rs

1//! Application-agnostic LMAX-pipeline server runtime.
2//!
3//! Groups the application-agnostic parts of the Melin server: the
4//! accept loop, frame reader, ack-policy wiring, admin
5//! endpoint, replication, and the optional DPDK transport. Generic
6//! over `A: Application` — the binary supplies a concrete app via
7//! [`server::run`] (or `server::run_dpdk` under `feature = "dpdk"`) along with caller-supplied
8//! [`StartupEvents`], `RequestDecoder`, `ResponseEncoder`, and event-
9//! publisher fn.
10//!
11//! The trading-side wiring (`ServerApp`, `ExchangeRequestDecoder`,
12//! `ExchangeResponseEncoder`, market-data firehose) lives in the
13//! separate `melin-server` crate.
14
15pub mod ack_policy;
16pub mod admin;
17mod buf_ring;
18mod client_frames;
19pub mod halt;
20pub mod layout;
21pub mod process;
22pub mod promotion;
23mod raft;
24mod raft_promotion;
25pub mod reader;
26pub mod replication;
27pub mod response;
28pub mod server;
29mod startup;
30mod uring_teardown;
31
32pub use startup::StartupEvents;
33
34#[cfg(feature = "dpdk")]
35pub mod dpdk_response;
36#[cfg(feature = "dpdk")]
37pub mod dpdk_transport;
38
39// The two wire bounds an application's codecs have to fit: the widest
40// request frame the readers accept, and the widest response frame the
41// response stage can encode. Re-exported here so an application can
42// assert against them at compile time, next to the bounds it declares
43// (`AppEvent::MAX_ENCODED_SIZE` is the journal's; these are the wire's).
44pub use client_frames::MAX_FRAME_SIZE;
45pub use response::MAX_RESPONSE_BUF;
46
47/// Control-plane event the accept loop, reader, and response stage
48/// exchange. Transport-agnostic — the payload is a socket fd + writer,
49/// not an app event — so both build modes refer to the same type.
50pub enum ControlEvent {
51    Connected {
52        connection_id: u64,
53        fd: std::os::unix::io::RawFd,
54        writer: melin_wire_protocol::blocking::BlockingFrameWriter<Box<dyn std::io::Write + Send>>,
55    },
56    Disconnected {
57        connection_id: u64,
58    },
59    /// Reader → response: the input pipeline was full when this
60    /// connection's frame arrived; deliver a `ServerBusy` notice through
61    /// the normal egress path. Routed through the response stage so
62    /// exactly one thread ever writes a client socket — a reader-side
63    /// send could land between the two halves of a partially-flushed
64    /// response frame and permanently desync the client's length-prefix
65    /// framing (2026-08 io_uring audit, review finding F3).
66    PipelineBusy {
67        connection_id: u64,
68    },
69}