feat: implement jetstream governance runtime parity semantics
This commit is contained in:
@@ -7,6 +7,8 @@ public sealed class JetStreamMetaGroup
|
|||||||
{
|
{
|
||||||
private readonly int _nodes;
|
private readonly int _nodes;
|
||||||
private readonly ConcurrentDictionary<string, byte> _streams = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, byte> _streams = new(StringComparer.Ordinal);
|
||||||
|
private int _leaderIndex = 1;
|
||||||
|
private long _leadershipVersion = 1;
|
||||||
|
|
||||||
public JetStreamMetaGroup(int nodes)
|
public JetStreamMetaGroup(int nodes)
|
||||||
{
|
{
|
||||||
@@ -25,13 +27,18 @@ public sealed class JetStreamMetaGroup
|
|||||||
{
|
{
|
||||||
Streams = _streams.Keys.OrderBy(x => x, StringComparer.Ordinal).ToArray(),
|
Streams = _streams.Keys.OrderBy(x => x, StringComparer.Ordinal).ToArray(),
|
||||||
ClusterSize = _nodes,
|
ClusterSize = _nodes,
|
||||||
|
LeaderId = $"meta-{_leaderIndex}",
|
||||||
|
LeadershipVersion = _leadershipVersion,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StepDown()
|
public void StepDown()
|
||||||
{
|
{
|
||||||
// Placeholder for parity API behavior; current in-memory meta group
|
_leaderIndex++;
|
||||||
// does not track explicit leader state.
|
if (_leaderIndex > Math.Max(_nodes, 1))
|
||||||
|
_leaderIndex = 1;
|
||||||
|
|
||||||
|
Interlocked.Increment(ref _leadershipVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,4 +46,6 @@ public sealed class MetaGroupState
|
|||||||
{
|
{
|
||||||
public IReadOnlyList<string> Streams { get; init; } = [];
|
public IReadOnlyList<string> Streams { get; init; } = [];
|
||||||
public int ClusterSize { get; init; }
|
public int ClusterSize { get; init; }
|
||||||
|
public string LeaderId { get; init; } = string.Empty;
|
||||||
|
public long LeadershipVersion { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public sealed class StreamManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyCollection<string> StreamNames => _streams.Keys.ToArray();
|
public IReadOnlyCollection<string> StreamNames => _streams.Keys.ToArray();
|
||||||
|
public MetaGroupState? GetMetaState() => _metaGroup?.GetState();
|
||||||
|
|
||||||
public IReadOnlyList<string> ListNames()
|
public IReadOnlyList<string> ListNames()
|
||||||
=> [.. _streams.Keys.OrderBy(x => x, StringComparer.Ordinal)];
|
=> [.. _streams.Keys.OrderBy(x => x, StringComparer.Ordinal)];
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using NATS.Server.JetStream.Cluster;
|
||||||
|
|
||||||
|
namespace NATS.Server.Tests.JetStream;
|
||||||
|
|
||||||
|
public class JetStreamMetaGovernanceStrictParityTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Meta_and_replica_governance_actions_reflect_committed_state_transitions()
|
||||||
|
{
|
||||||
|
var meta = new JetStreamMetaGroup(3);
|
||||||
|
var before = meta.GetState();
|
||||||
|
|
||||||
|
await meta.ProposeCreateStreamAsync(new NATS.Server.JetStream.Models.StreamConfig
|
||||||
|
{
|
||||||
|
Name = "ORDERS_GOV",
|
||||||
|
Subjects = ["orders.gov"],
|
||||||
|
}, default);
|
||||||
|
meta.StepDown();
|
||||||
|
var after = meta.GetState();
|
||||||
|
|
||||||
|
after.Streams.ShouldContain("ORDERS_GOV");
|
||||||
|
after.LeaderId.ShouldNotBe(before.LeaderId);
|
||||||
|
after.LeadershipVersion.ShouldBe(before.LeadershipVersion + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using NATS.Server.JetStream.Cluster;
|
||||||
|
|
||||||
|
namespace NATS.Server.Tests.JetStream;
|
||||||
|
|
||||||
|
public class JetStreamReplicaGovernanceStrictParityTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Meta_and_replica_governance_actions_reflect_committed_state_transitions()
|
||||||
|
{
|
||||||
|
var group = new StreamReplicaGroup("ORDERS_GOV", replicas: 3);
|
||||||
|
var beforeLeader = group.Leader.Id;
|
||||||
|
|
||||||
|
await group.StepDownAsync(default);
|
||||||
|
group.Leader.Id.ShouldNotBe(beforeLeader);
|
||||||
|
|
||||||
|
var index = await group.ProposeAsync("set placement", default);
|
||||||
|
index.ShouldBeGreaterThan(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user