Skip to main content

Module replication

Module replication 

Source
Expand description

Replication — synchronous input-stream streaming from primary to replica.

The primary’s JournalStage encodes each InputSlot it just durably journaled into a wire-ready InputBatch frame in the replication ring (separately from the journal-codec bytes it writes to disk). The ReplicationSender thread forwards those frames as-is over TCP/DPDK — no decode + re-encode on the hot path. The replica decodes the frames straight back into InputSlots, publishes them to its local input disruptor with the primary’s pre-assigned sequences and timestamps, and the replica’s JournalStage re-encodes them through its own writer for byte-exact-on-replay durability.

§Wire Protocol

Length-prefixed frames, little-endian, over a dedicated TCP connection (or DPDK pipe). The full InputBatch payload layout lives in melin_transport_core::replication::protocol / melin_transport_core::replication_wire.

§Auth (before handshake)

  • Challenge (Primary → Replica): [len:u32][0x03][nonce:[u8;32]]
  • ChallengeResponse (Replica → Primary): [len:u32][0x04][signature:[u8;64]][pubkey:[u8;32]]
  • AuthOk (Primary → Replica): [len:u32][0x05]
  • AuthFailed (Primary → Replica): [len:u32][0x06]

§Replica → Primary

  • Handshake: [len:u32][0x01][last_sequence:u64][chain_hash:[u8;32]]
  • Ack: [len:u32][0x02][acked_sequence:u64][in_memory_sequence:u64]

§Primary → Replica

  • StreamStart: [len:u32][0x10][start_sequence:u64][segment_start_sequence:u64][anchor_hash:[u8;32]][epoch:u64][genesis_known:u8][genesis_entries:u64] — the segment header identity a fresh replica creates its journal with (lineage origin for full catch-up, the seeded segment’s identity after a snapshot transfer), and the lineage’s genesis length, which a fresh replica records and one with a journal checks against its own
  • NeedSnapshot: [len:u32][0x11]
  • HashMismatch: [len:u32][0x12] — divergent replica journal; the replica archives its lineage, then the snapshot flow follows
  • SnapshotBegin: [len:u32][0x13][snapshot_len:u64][snap_sequence:u64][snap_chain_hash:[u8;32]]
  • SnapshotChunk: [len:u32][0x14][data...]
  • SnapshotEnd: [len:u32][0x15][crc32c:u32]
  • Rotate: [len:u32][0x16][boundary_seq:u64][tail_hash:[u8;32]] — primary-driven rotation, verified + adopted by the replica
  • ChainCheck: [len:u32][0x17][sequence:u64][chain_hash:[u8;32]] — periodic live-stream chain validation
  • SegmentSeedBegin: [len:u32][0x18][seed_len:u64] — raw byte prefix of the primary’s segment containing the snapshot boundary; body rides SnapshotChunk frames, ends with SnapshotEnd
  • InputBatch: [len:u32][0x21][count:u16][slot...] — see transport-core::replication_wire for the per-slot layout
  • Heartbeat: [len:u32][0x30][sequence:u64]

§Limitations

  • Dual replication (up to 2 replicas in parallel)

See docs/replication.md for the full design document and limitation details.

Structs§

ReplicaControlPlane
The handles a replica’s receive loop shares with the rest of the node — the admin endpoint and the control-plane raft driver. Bundled (rather than five positional parameters) because they always travel together through the kernel-TCP and DPDK receiver signatures, and a transposition between same-typed flags is exactly the bug a bundle prevents.
ReplicationListener
Owned state for the replication sender thread. A TCP listener guaranteed non-blocking: the only constructor sets the flag, so the guarantee is carried by the type. run_sender’s accept loop polls the shutdown flag between accepts — handed a blocking listener it would park inside accept() and only observe shutdown when the next replica happened to dial in. This newtype makes that state unrepresentable instead of documenting it away.
ReplicationMetrics
Per-slot replication metrics exposed via the health endpoint.
Sender

Functions§

run_receiver
run_sender
Run the replication sender. Listens for replica connections, streams journal data batches, processes acks, and updates the replication cursor.

Type Aliases§

ReceiverResult
Outcome of run_receiver: None = clean shutdown, Some = promotion.