feat: implement raft snapshot catchup
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
8
src/NATS.Server/Raft/RaftSnapshot.cs
Normal file
8
src/NATS.Server/Raft/RaftSnapshot.cs
Normal 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; } = [];
|
||||
}
|
||||
17
src/NATS.Server/Raft/RaftSnapshotStore.cs
Normal file
17
src/NATS.Server/Raft/RaftSnapshotStore.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user