Add persistent view_number/commit_index and WAL replay on startup

On startup, the server now loads view_number, last_normal_view and
commit_index from a durable state file (vsr.state) and replays the
WAL up to the saved commit_index when the log is intact. If the log
is corrupt (checksum failure), the server truncates it and enters
recovery mode to fetch a valid log from peers.

ViewAndCommit follows the same persistence pattern as raft's
TermAndVote: fixed-size record with FNV-1a checksum, written with
fsync on every mutation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-22 17:04:07 +01:00
co-authored by Claude Opus 4.6
parent 5e7ab662d1
commit 9bec97715a
4 changed files with 195 additions and 15 deletions
+19 -2
View File
@@ -35,8 +35,10 @@ typedef struct {
void wal_init(WAL *wal);
// Initialize a WAL from an on-disk file. Recovers valid entries,
// discards partial/corrupted trailing entries.
int wal_init_from_file(WAL *wal, string file);
// discards partial/corrupted trailing entries. If was_truncated is
// non-NULL, *was_truncated is set to true when entries were discarded
// due to corruption (not just a partial trailing write).
int wal_init_from_file(WAL *wal, string file, bool *was_truncated);
// Initialize a WAL from network data (memory-only, no file).
int wal_init_from_network(WAL *wal, void *src, int num);
@@ -62,4 +64,19 @@ int wal_replace(WAL *wal, WALEntry *entries, int count);
int wal_entry_count(WAL *wal);
WALEntry *wal_peek_entry(WAL *wal, int idx);
// Persistent view_number, last_normal_view and commit_index,
// analogous to raft's TermAndVote. Backed by a small file
// ("vsr.state") with a checksum for integrity.
typedef struct {
uint64_t view_number;
uint64_t last_normal_view;
int commit_index;
Handle handle;
} ViewAndCommit;
int view_and_commit_init(ViewAndCommit *vc, string file);
void view_and_commit_free(ViewAndCommit *vc);
int set_view_and_commit(ViewAndCommit *vc, uint64_t view_number,
uint64_t last_normal_view, int commit_index);
#endif // WAL_INCLUDED