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 application-side wiring (the `Application` itself, its decoder
12//! and encoder, any event publisher) lives in the application's own
13//! crate — see the examples under `crates/examples/`.
14
15pub mod ack_policy;
16pub mod admin;
17mod buf_ring;
18pub mod client_auth;
19mod client_frames;
20mod durability_gate;
21pub mod halt;
22pub mod layout;
23pub mod process;
24pub mod promotion;
25mod raft;
26mod raft_promotion;
27pub mod reader;
28pub mod replication;
29pub mod response;
30mod response_frame;
31pub mod server;
32mod startup;
33#[cfg(test)]
34mod test_roles;
35mod uring_teardown;
36
37pub use startup::StartupEvents;
38
39#[cfg(feature = "dpdk")]
40pub mod dpdk_response;
41#[cfg(feature = "dpdk")]
42pub mod dpdk_transport;
43
44// The two wire bounds an application's codecs have to fit: the widest
45// request body the readers hand a decoder, and the widest response body
46// the response stages give an encoder room for — both after the
47// protocol's framing, which the runtime reads and writes itself.
48// Re-exported here so an application can assert against them at compile
49// time, next to the bounds it declares (`AppEvent::MAX_ENCODED_SIZE` is
50// the journal's; these are the wire's). `MAX_FRAME_SIZE` is the whole
51// request frame, for a program that reads client frames itself.
52pub use client_frames::{MAX_FRAME_SIZE, MAX_REQUEST_BODY};
53pub use response_frame::MAX_RESPONSE_BODY;
54
55/// Control-plane event the accept loop, reader, and response stage
56/// exchange. Transport-agnostic — the payload is a socket fd + writer,
57/// not an app event — so both build modes refer to the same type.
58pub enum ControlEvent {
59 Connected {
60 connection_id: u64,
61 fd: std::os::unix::io::RawFd,
62 writer: melin_wire_protocol::blocking::BlockingFrameWriter<Box<dyn std::io::Write + Send>>,
63 },
64 Disconnected {
65 connection_id: u64,
66 },
67 /// Reader → response: the input pipeline was full when this
68 /// connection's frame arrived; deliver a `ServerBusy` notice through
69 /// the normal egress path. Routed through the response stage so
70 /// exactly one thread ever writes a client socket — a reader-side
71 /// send could land between the two halves of a partially-flushed
72 /// response frame and permanently desync the client's length-prefix
73 /// framing (2026-08 io_uring audit, review finding F3).
74 PipelineBusy {
75 connection_id: u64,
76 },
77}