Expand description
Node-local hinted-handoff store.
When a write request fans out to a peer in
crate::cluster::peer::PeerState::Down or to a peer whose
outbound channel is closed, the dispatcher records a hint:
the on-the-wire request bytes, the index of the intended
peer, and an absolute expiry deadline. A background task
periodically:
- drains hints destined for any peer that has returned to
crate::cluster::peer::PeerState::Normaland ships them over the same per-peer outbound channel the dispatcher would have used; - drops hints that have aged past their
hint_ttl_secondsso the in-memory store stays bounded.
The store has two constructors. HintStore::new is the
RAM-only variant: hints live only in the per-peer queues and
are lost if the coordinator restarts. HintStore::open
adds a durable backend so queued hints survive a restart.
§Durable backend
The durable backend keeps one append-only segment file per
peer under <dir>/peer-<idx>.hints. Each record frames a
single hint as a little-endian u32 body length, a
little-endian u32 CRC-32 (IEEE) of the body, and the body
itself: a little-endian u64 wall-clock deadline (Unix
milliseconds) followed by the raw payload bytes. The peer
index is encoded in the file name, not the record.
HintStore::enqueuewrite-through appends one record to the target peer’s segment.HintStore::take_forreturns the live hints and then removes that peer’s segment (the hints have been handed off; a failed delivery is re-enqueued by the caller, which re-appends a fresh segment).HintStore::expire_nowrewrites each affected peer’s segment from the surviving in-memory hints so the on-disk log is compacted and never grows pastmax_bytes.
HintStore::open replays every segment in dir back into
the in-memory queues at startup. The deadline is stored as a
wall-clock instant so it survives the process boundary; on
replay each deadline is re-anchored to the current monotonic
clock and any hint whose wall-clock deadline has already
passed is dropped.
§Torn-tail safety
A crash mid-append can leave a torn trailing record. Replay
detects this two ways: a record whose framed length cannot
be read in full (a short read before the body completes) is
discarded as a clean EOF, and a record whose body CRC does
not match the stored CRC is treated as torn. In both cases
replay stops at the first damaged record and keeps every
intact record before it. A torn tail never panics and never
surfaces an error from HintStore::open.
§Examples
use std::time::{Duration, Instant};
use dynomite::cluster::hints::HintStore;
let store = HintStore::new(1024);
store.enqueue(7, b"*3\r\n$3\r\nSET\r\n$1\r\nk\r\n$1\r\nv\r\n".to_vec(), Duration::from_secs(60))
.expect("under capacity");
let drained = store.take_for(7);
assert_eq!(drained.len(), 1);
assert_eq!(store.expire_now(Instant::now()), 0);Structs§
- Hint
- One pending hint.
- Hint
Store - Node-local hint store.
- Hint
Store Stats - Snapshot of the store’s current size.
Enums§
- Hint
Store Error - Errors produced by
HintStore::enqueue. - Hint
Store Open Error - Errors produced by
HintStore::open.