README

Lfan-ke/raft-moonbit/storage does not have a README file

#
LogStore

pub(open) trait LogStore {
fn persist(Self, Persisted) -> Unit
fn restore(Self) -> Persisted?
}

Durable storage for a node's persistent state. A real deployment backs this with a file or a database; the tests use an in-memory implementation. Keeping it a trait decouples the consensus core from any particular I/O.

#
RaftStorage

pub(open) trait RaftStorage {
fn initial_state(Self) ->
HardState

fn storage_entries(Self, UInt64, UInt64, UInt64) -> Array[
Entry
] raise StorageError
fn storage_term(Self, UInt64) -> UInt64 raise StorageError
fn first_index(Self) -> UInt64
fn last_index(Self) -> UInt64
fn storage_snapshot(Self) ->
Snapshot
raise StorageError
fn append(Self, Array[
Entry
]) -> Unit
}

Read access to a node's durable log, modelled on etcd's Storage interface. The consensus core reads entries, terms and the snapshot back through this trait, which lets the same core run over memory, a file or a database.

The index/term accessors raise StorageError so a compacted index is reported distinctly from an unavailable one, exactly as etcd's Storage contract requires.

#
WalStore

pub(open) trait WalStore {
fn append_record(Self, WalRecord) -> Unit
fn load(Self) -> Array[WalRecord]
}

Durable, append-only write-ahead log. Implemented over a file in production; the in-memory MemWal in the tests is used for tests and single-process runs.

#
StorageError

pub(all) suberror StorageError {
Compacted
Unavailable
SnapOutOfDate
SnapshotTemporarilyUnavailable
} derive(Eq)

The failure modes a RaftStorage can report, one variant per distinguishable condition so a caller can tell "this index is gone forever" apart from "this index has not arrived yet" — a distinction etcd draws with distinct sentinel errors and one the consensus core depends on to decide between sending a snapshot and simply waiting.

#
MemoryStorage

An in-memory RaftStorage. ents[0] is a sentinel whose index and term are the snapshot baseline, so ents[i] always holds the entry at absolute index ents[0].index + i. This mirrors etcd's MemoryStorage layout, which keeps index arithmetic branch-free.

#
MemoryStorage::append

Append entries to the log, overwriting any conflicting suffix. Entries whose indices fall at or before the sentinel are already compacted and are dropped; a gap between the log and the incoming entries is a programming error and aborts, matching etcd's panic.

#
MemoryStorage::apply_snapshot

fn MemoryStorage::apply_snapshot(self : MemoryStorage, snapshot :
Snapshot
) -> Unit raise StorageError

Replace the whole log with a snapshot baseline, resetting the sentinel to the snapshot's index and term (Raft §7). A snapshot no newer than the one already stored is rejected with SnapOutOfDate.

#
MemoryStorage::compact

fn MemoryStorage::compact(self : MemoryStorage, compact_index : UInt64) -> Unit raise StorageError

Discard every entry at or before compact_index, moving the sentinel up to that index. An index at or before the current sentinel is Compacted; one past the last entry aborts (etcd panics), since it is a caller error.

#
MemoryStorage::create_snapshot

fn MemoryStorage::create_snapshot(self : MemoryStorage, index : UInt64, data : Bytes, conf_state? :
ConfState
?) ->
Snapshot
raise StorageError

Build a snapshot at index carrying data, remember it, and return it. An index at or before the current snapshot is SnapOutOfDate; one past the last entry aborts (etcd panics).

#
MemoryStorage::from_ents

Build storage directly over a given entry array, treating ents[0] as the compaction sentinel. Mirrors etcd's &MemoryStorage{ents: ents} test setup.

#
MemoryStorage::new

Create empty storage: an initial HardState, the empty snapshot, and a lone sentinel entry at index 0.

#
MemoryStorage::raw_ents

The raw entry array, sentinel included. Test-facing, to assert the exact post-compaction/append layout the way etcd's storage tests do.

#
MemoryStorage::seed_snapshot

fn MemoryStorage::seed_snapshot(self : MemoryStorage, snapshot :
Snapshot
) -> Unit

Install a snapshot baseline unconditionally, resetting the sentinel to its index and term. This is the write half of apply_snapshot without the out-of-date guard, for seeding a freshly created storage whose empty baseline cannot predate anything.

#
MemoryStorage::set_hard_state

Record the HardState (term, vote, commit) for the next restart.

#
MemoryStorage::set_snapshot_pending

fn MemoryStorage::set_snapshot_pending(self : MemoryStorage, pending : Bool) -> Unit

Report the snapshot as not-yet-ready (true) or ready (false). Lets a backend signal that storage_snapshot() should be retried rather than treated as an error.

#
MemoryStorage::slice

fn MemoryStorage::slice(self : MemoryStorage, lo : UInt64, hi : UInt64) -> Array[
Entry
]

A best-effort, clamping read of entries with indices in [lo, hi): indices at or before the sentinel and past the last entry are simply skipped rather than raising. Used where an approximate window is wanted without the strict etcd error contract.

#
Persisted

pub(all) struct Persisted {
term : UInt64
voted_for : String?
log : Array[
Entry
]
}

The persistent state a Raft node must save to stable storage before responding to any RPC (Raft §5.3): the current term, the vote cast in that term, and the log. It is exactly what a node reloads to recover after a crash.

#
WalRecord

One record in the write-ahead log. A real Raft node appends these to a file (fsync'd before it replies to any RPC) and replays them in order after a crash to rebuild exactly the state it had promised (Raft §5.3, §7). A WalSnapshot marks a compaction baseline; the WalEntry records after it carry the log tail; WalHardState records the term/vote/commit at the time.