feat(jetstream): add API leader forwarding and stream purge options (C7+C8)

C7: JetStreamApiRouter now checks leadership before mutating operations.
Non-leader nodes return error code 10003 with a leader_hint field.
JetStreamMetaGroup gains IsLeader() and Leader for cluster-aware routing.

C8: StreamApiHandlers.HandlePurge accepts PurgeRequest options (filter,
seq, keep). StreamManager.PurgeEx implements subject-filtered purge,
sequence-based purge, keep-last-N, and filter+keep combinations.
This commit is contained in:
Joseph Doherty
2026-02-24 15:22:22 -05:00
parent d259a2d03e
commit 7116988d03
8 changed files with 627 additions and 5 deletions

View File

@@ -6,15 +6,34 @@ namespace NATS.Server.JetStream.Cluster;
public sealed class JetStreamMetaGroup
{
private readonly int _nodes;
private readonly int _selfIndex;
private readonly ConcurrentDictionary<string, byte> _streams = new(StringComparer.Ordinal);
private int _leaderIndex = 1;
private long _leadershipVersion = 1;
public JetStreamMetaGroup(int nodes)
: this(nodes, selfIndex: 1)
{
}
public JetStreamMetaGroup(int nodes, int selfIndex)
{
_nodes = nodes;
_selfIndex = selfIndex;
}
/// <summary>
/// Returns true when this node is the current meta-group leader.
/// Go reference: jetstream_api.go:200-300 — leader check before mutating operations.
/// </summary>
public bool IsLeader() => _leaderIndex == _selfIndex;
/// <summary>
/// Returns the leader identifier string, e.g. "meta-1".
/// Used to populate the leader_hint field in not-leader error responses.
/// </summary>
public string Leader => $"meta-{_leaderIndex}";
public Task ProposeCreateStreamAsync(StreamConfig config, CancellationToken ct)
{
_streams[config.Name] = 0;