feat: execute post-baseline jetstream parity plan
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user