Skip to main content

Module hints

Module hints 

Source
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::Normal and ships them over the same per-peer outbound channel the dispatcher would have used;
  • drops hints that have aged past their hint_ttl_seconds so 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::enqueue write-through appends one record to the target peer’s segment.
  • HintStore::take_for returns 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_now rewrites each affected peer’s segment from the surviving in-memory hints so the on-disk log is compacted and never grows past max_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.
HintStore
Node-local hint store.
HintStoreStats
Snapshot of the store’s current size.

Enums§

HintStoreError
Errors produced by HintStore::enqueue.
HintStoreOpenError
Errors produced by HintStore::open.