feat: execute post-baseline jetstream parity plan

This commit is contained in:
Joseph Doherty
2026-02-23 12:11:19 -05:00
parent c3763e83d6
commit b41e6ff320
58 changed files with 1430 additions and 102 deletions

View File

@@ -8,11 +8,13 @@ public sealed class RaftNode
private readonly RaftSnapshotStore _snapshotStore = new();
private readonly IRaftTransport? _transport;
private readonly string? _persistDirectory;
private readonly HashSet<string> _members = new(StringComparer.Ordinal);
public string Id { get; }
public int Term => TermState.CurrentTerm;
public bool IsLeader => Role == RaftRole.Leader;
public RaftRole Role { get; private set; } = RaftRole.Follower;
public IReadOnlyCollection<string> Members => _members;
public RaftTermState TermState { get; } = new();
public long AppliedIndex { get; set; }
public RaftLog Log { get; private set; } = new();
@@ -22,14 +24,22 @@ public sealed class RaftNode
Id = id;
_transport = transport;
_persistDirectory = persistDirectory;
_members.Add(id);
}
public void ConfigureCluster(IEnumerable<RaftNode> peers)
{
_cluster.Clear();
_cluster.AddRange(peers);
_members.Clear();
foreach (var peer in peers)
_members.Add(peer.Id);
}
public void AddMember(string memberId) => _members.Add(memberId);
public void RemoveMember(string memberId) => _members.Remove(memberId);
public void StartElection(int clusterSize)
{
Role = RaftRole.Candidate;
@@ -48,6 +58,15 @@ public sealed class RaftNode
return new VoteResponse { Granted = true };
}
public void ReceiveHeartbeat(int term)
{
if (term < TermState.CurrentTerm)
return;
TermState.CurrentTerm = term;
Role = RaftRole.Follower;
}
public void ReceiveVote(VoteResponse response, int clusterSize = 3)
{
if (!response.Granted)

View File

@@ -2,6 +2,9 @@ namespace NATS.Server.Raft;
public sealed class RaftReplicator
{
public static long BacktrackNextIndex(long nextIndex)
=> Math.Max(1, nextIndex - 1);
public int Replicate(RaftLogEntry entry, IReadOnlyList<RaftNode> followers)
{
var acknowledgements = 0;

View File

@@ -4,6 +4,7 @@ public interface IRaftTransport
{
Task<IReadOnlyList<AppendResult>> AppendEntriesAsync(string leaderId, IReadOnlyList<string> followerIds, RaftLogEntry entry, CancellationToken ct);
Task<VoteResponse> RequestVoteAsync(string candidateId, string voterId, VoteRequest request, CancellationToken ct);
Task InstallSnapshotAsync(string leaderId, string followerId, RaftSnapshot snapshot, CancellationToken ct);
}
public sealed class InMemoryRaftTransport : IRaftTransport
@@ -41,4 +42,23 @@ public sealed class InMemoryRaftTransport : IRaftTransport
return Task.FromResult(new VoteResponse { Granted = false });
}
public async Task InstallSnapshotAsync(string leaderId, string followerId, RaftSnapshot snapshot, CancellationToken ct)
{
_ = leaderId;
if (_nodes.TryGetValue(followerId, out var node))
await node.InstallSnapshotAsync(snapshot, ct);
}
public async Task AppendHeartbeatAsync(string leaderId, IReadOnlyList<string> followerIds, int term, CancellationToken ct)
{
_ = leaderId;
foreach (var followerId in followerIds)
{
if (_nodes.TryGetValue(followerId, out var node))
node.ReceiveHeartbeat(term);
}
await Task.CompletedTask;
}
}