feat: implement raft snapshot catchup

This commit is contained in:
Joseph Doherty
2026-02-23 06:13:08 -05:00
parent ecc4752c07
commit 005600b9b8
6 changed files with 93 additions and 1 deletions

View File

@@ -3,12 +3,13 @@ namespace NATS.Server.Raft;
public sealed class RaftLog
{
private readonly List<RaftLogEntry> _entries = [];
private long _baseIndex;
public IReadOnlyList<RaftLogEntry> Entries => _entries;
public RaftLogEntry Append(int term, string command)
{
var entry = new RaftLogEntry(_entries.Count + 1, term, command);
var entry = new RaftLogEntry(_baseIndex + _entries.Count + 1, term, command);
_entries.Add(entry);
return entry;
}
@@ -20,6 +21,12 @@ public sealed class RaftLog
_entries.Add(entry);
}
public void ReplaceWithSnapshot(RaftSnapshot snapshot)
{
_entries.Clear();
_baseIndex = snapshot.LastIncludedIndex;
}
}
public sealed record RaftLogEntry(long Index, int Term, string Command);

View File

@@ -5,6 +5,7 @@ public sealed class RaftNode
private int _votesReceived;
private readonly List<RaftNode> _cluster = [];
private readonly RaftReplicator _replicator = new();
private readonly RaftSnapshotStore _snapshotStore = new();
public string Id { get; }
public int Term => TermState.CurrentTerm;
@@ -77,6 +78,24 @@ public sealed class RaftNode
Log.AppendReplicated(entry);
}
public async Task<RaftSnapshot> CreateSnapshotAsync(CancellationToken ct)
{
var snapshot = new RaftSnapshot
{
LastIncludedIndex = AppliedIndex,
LastIncludedTerm = Term,
};
await _snapshotStore.SaveAsync(snapshot, ct);
return snapshot;
}
public Task InstallSnapshotAsync(RaftSnapshot snapshot, CancellationToken ct)
{
Log.ReplaceWithSnapshot(snapshot);
AppliedIndex = snapshot.LastIncludedIndex;
return _snapshotStore.SaveAsync(snapshot, ct);
}
public void RequestStepDown()
{
Role = RaftRole.Follower;

View File

@@ -0,0 +1,8 @@
namespace NATS.Server.Raft;
public sealed class RaftSnapshot
{
public long LastIncludedIndex { get; init; }
public int LastIncludedTerm { get; init; }
public byte[] Data { get; init; } = [];
}

View File

@@ -0,0 +1,17 @@
namespace NATS.Server.Raft;
public sealed class RaftSnapshotStore
{
private RaftSnapshot? _snapshot;
public Task SaveAsync(RaftSnapshot snapshot, CancellationToken ct)
{
_snapshot = snapshot;
return Task.CompletedTask;
}
public Task<RaftSnapshot?> LoadAsync(CancellationToken ct)
{
return Task.FromResult(_snapshot);
}
}