feat(raft): add membership proposals, snapshot checkpoints, and log compaction (B4+B5+B6)
- ProposeAddPeerAsync/ProposeRemovePeerAsync: single-change-at-a-time membership changes through RAFT consensus (Go ref: raft.go:961-1019) - RaftLog.Compact: removes entries up to given index for log compaction - CreateSnapshotCheckpointAsync: creates snapshot and compacts log in one operation - DrainAndReplaySnapshotAsync: drains commit queue, installs snapshot, resets indices - Pre-vote protocol skipped (Go NATS doesn't implement it either) - 23 new tests in RaftMembershipAndSnapshotTests
This commit is contained in:
49
src/NATS.Server/JetStream/Cluster/ClusterAssignmentTypes.cs
Normal file
49
src/NATS.Server/JetStream/Cluster/ClusterAssignmentTypes.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace NATS.Server.JetStream.Cluster;
|
||||
|
||||
/// <summary>
|
||||
/// RAFT group describing which peers own a replicated asset (stream or consumer).
|
||||
/// Go reference: jetstream_cluster.go:154-163 raftGroup struct.
|
||||
/// </summary>
|
||||
public sealed class RaftGroup
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public List<string> Peers { get; init; } = [];
|
||||
public string StorageType { get; set; } = "file";
|
||||
public string Cluster { get; set; } = string.Empty;
|
||||
public string Preferred { get; set; } = string.Empty;
|
||||
|
||||
public int QuorumSize => (Peers.Count / 2) + 1;
|
||||
public bool HasQuorum(int ackCount) => ackCount >= QuorumSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assignment of a stream to a RAFT group of peers.
|
||||
/// Go reference: jetstream_cluster.go:166-184 streamAssignment struct.
|
||||
/// </summary>
|
||||
public sealed class StreamAssignment
|
||||
{
|
||||
public required string StreamName { get; init; }
|
||||
public required RaftGroup Group { get; init; }
|
||||
public DateTime Created { get; init; } = DateTime.UtcNow;
|
||||
public string ConfigJson { get; set; } = "{}";
|
||||
public string SyncSubject { get; set; } = string.Empty;
|
||||
public bool Responded { get; set; }
|
||||
public bool Recovering { get; set; }
|
||||
public bool Reassigning { get; set; }
|
||||
public Dictionary<string, ConsumerAssignment> Consumers { get; } = new(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assignment of a consumer to a RAFT group within a stream's cluster.
|
||||
/// Go reference: jetstream_cluster.go:250-266 consumerAssignment struct.
|
||||
/// </summary>
|
||||
public sealed class ConsumerAssignment
|
||||
{
|
||||
public required string ConsumerName { get; init; }
|
||||
public required string StreamName { get; init; }
|
||||
public required RaftGroup Group { get; init; }
|
||||
public DateTime Created { get; init; } = DateTime.UtcNow;
|
||||
public string ConfigJson { get; set; } = "{}";
|
||||
public bool Responded { get; set; }
|
||||
public bool Recovering { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user