feat: implement raft log replication and apply
This commit is contained in:
@@ -3,18 +3,27 @@ namespace NATS.Server.Raft;
|
||||
public sealed class RaftNode
|
||||
{
|
||||
private int _votesReceived;
|
||||
private readonly List<RaftNode> _cluster = [];
|
||||
private readonly RaftReplicator _replicator = new();
|
||||
|
||||
public string Id { get; }
|
||||
public int Term => TermState.CurrentTerm;
|
||||
public RaftRole Role { get; private set; } = RaftRole.Follower;
|
||||
public RaftTermState TermState { get; } = new();
|
||||
public long AppliedIndex { get; set; }
|
||||
public RaftLog Log { get; } = new();
|
||||
|
||||
public RaftNode(string id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public void ConfigureCluster(IEnumerable<RaftNode> peers)
|
||||
{
|
||||
_cluster.Clear();
|
||||
_cluster.AddRange(peers);
|
||||
}
|
||||
|
||||
public void StartElection(int clusterSize)
|
||||
{
|
||||
Role = RaftRole.Candidate;
|
||||
@@ -42,15 +51,41 @@ public sealed class RaftNode
|
||||
TryBecomeLeader(clusterSize);
|
||||
}
|
||||
|
||||
private void TryBecomeLeader(int clusterSize)
|
||||
public async ValueTask<long> ProposeAsync(string command, CancellationToken ct)
|
||||
{
|
||||
var quorum = (clusterSize / 2) + 1;
|
||||
if (_votesReceived >= quorum)
|
||||
Role = RaftRole.Leader;
|
||||
if (Role != RaftRole.Leader)
|
||||
throw new InvalidOperationException("Only leader can propose entries.");
|
||||
|
||||
var entry = Log.Append(TermState.CurrentTerm, command);
|
||||
var followers = _cluster.Where(n => n.Id != Id).ToList();
|
||||
var acknowledgements = _replicator.Replicate(entry, followers);
|
||||
|
||||
var quorum = (_cluster.Count / 2) + 1;
|
||||
if (acknowledgements + 1 >= quorum)
|
||||
{
|
||||
AppliedIndex = entry.Index;
|
||||
foreach (var node in _cluster)
|
||||
node.AppliedIndex = Math.Max(node.AppliedIndex, entry.Index);
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
return entry.Index;
|
||||
}
|
||||
|
||||
public void ReceiveReplicatedEntry(RaftLogEntry entry)
|
||||
{
|
||||
Log.AppendReplicated(entry);
|
||||
}
|
||||
|
||||
public void RequestStepDown()
|
||||
{
|
||||
Role = RaftRole.Follower;
|
||||
}
|
||||
|
||||
private void TryBecomeLeader(int clusterSize)
|
||||
{
|
||||
var quorum = (clusterSize / 2) + 1;
|
||||
if (_votesReceived >= quorum)
|
||||
Role = RaftRole.Leader;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user