diff --git a/src/NATS.Server/Subscriptions/RoutedSubKey.cs b/src/NATS.Server/Subscriptions/RoutedSubKey.cs new file mode 100644 index 0000000..6ff55bf --- /dev/null +++ b/src/NATS.Server/Subscriptions/RoutedSubKey.cs @@ -0,0 +1,7 @@ +namespace NATS.Server.Subscriptions; + +internal readonly record struct RoutedSubKey(string RouteId, string Account, string Subject, string? Queue) +{ + public static RoutedSubKey FromRemoteSubscription(RemoteSubscription sub) + => new(sub.RouteId, sub.Account, sub.Subject, sub.Queue); +} diff --git a/src/NATS.Server/Subscriptions/SubList.cs b/src/NATS.Server/Subscriptions/SubList.cs index ae5af7e..b18e3fc 100644 --- a/src/NATS.Server/Subscriptions/SubList.cs +++ b/src/NATS.Server/Subscriptions/SubList.cs @@ -16,7 +16,7 @@ public sealed class SubList : IDisposable private readonly ReaderWriterLockSlim _lock = new(); private readonly TrieLevel _root = new(); private readonly SubListCacheSweeper _sweeper = new(); - private readonly Dictionary _remoteSubs = new(StringComparer.Ordinal); + private readonly Dictionary _remoteSubs = []; private Dictionary? _cache = new(StringComparer.Ordinal); private uint _count; private volatile bool _disposed; @@ -31,8 +31,6 @@ public sealed class SubList : IDisposable private readonly Dictionary>> _queueRemoveNotifications = new(StringComparer.Ordinal); private readonly record struct CachedResult(SubListResult Result, long Generation); - internal readonly record struct RoutedSubKeyInfo(string RouteId, string Account, string Subject, string? Queue); - public event Action? InterestChanged; public SubList() @@ -178,7 +176,7 @@ public sealed class SubList : IDisposable _lock.EnterWriteLock(); try { - var key = BuildRoutedSubKey(sub.RouteId, sub.Account, sub.Subject, sub.Queue); + var key = RoutedSubKey.FromRemoteSubscription(sub); var changed = false; if (sub.IsRemoval) { @@ -223,7 +221,7 @@ public sealed class SubList : IDisposable _lock.EnterWriteLock(); try { - var key = BuildRoutedSubKey(sub.RouteId, sub.Account, sub.Subject, sub.Queue); + var key = RoutedSubKey.FromRemoteSubscription(sub); if (!_remoteSubs.TryGetValue(key, out var existing)) return; @@ -240,28 +238,6 @@ public sealed class SubList : IDisposable } } - internal static string BuildRoutedSubKey(string routeId, string account, string subject, string? queue) - => $"{routeId}|{account}|{subject}|{queue}"; - - internal static string? GetAccNameFromRoutedSubKey(string routedSubKey) - => GetRoutedSubKeyInfo(routedSubKey)?.Account; - - internal static RoutedSubKeyInfo? GetRoutedSubKeyInfo(string routedSubKey) - { - if (string.IsNullOrWhiteSpace(routedSubKey)) - return null; - - var parts = routedSubKey.Split('|'); - if (parts.Length != 4) - return null; - - if (parts[0].Length == 0 || parts[1].Length == 0 || parts[2].Length == 0) - return null; - - var queue = parts[3].Length == 0 ? null : parts[3]; - return new RoutedSubKeyInfo(parts[0], parts[1], parts[2], queue); - } - public int RemoveRemoteSubs(string routeId) { _lock.EnterWriteLock(); @@ -270,8 +246,7 @@ public sealed class SubList : IDisposable var removed = 0; foreach (var kvp in _remoteSubs.ToArray()) { - var info = GetRoutedSubKeyInfo(kvp.Key); - if (info == null || !string.Equals(info.Value.RouteId, routeId, StringComparison.Ordinal)) + if (!string.Equals(kvp.Key.RouteId, routeId, StringComparison.Ordinal)) continue; if (_remoteSubs.Remove(kvp.Key)) @@ -304,12 +279,8 @@ public sealed class SubList : IDisposable var removed = 0; foreach (var kvp in _remoteSubs.ToArray()) { - var info = GetRoutedSubKeyInfo(kvp.Key); - if (info == null) - continue; - - if (!string.Equals(info.Value.RouteId, routeId, StringComparison.Ordinal) - || !string.Equals(info.Value.Account, account, StringComparison.Ordinal)) + if (!string.Equals(kvp.Key.RouteId, routeId, StringComparison.Ordinal) + || !string.Equals(kvp.Key.Account, account, StringComparison.Ordinal)) { continue; } diff --git a/tests/NATS.Server.Clustering.Tests/Routes/RouteRemoteSubCleanupParityBatch2Tests.cs b/tests/NATS.Server.Clustering.Tests/Routes/RouteRemoteSubCleanupParityBatch2Tests.cs index f363389..f20649a 100644 --- a/tests/NATS.Server.Clustering.Tests/Routes/RouteRemoteSubCleanupParityBatch2Tests.cs +++ b/tests/NATS.Server.Clustering.Tests/Routes/RouteRemoteSubCleanupParityBatch2Tests.cs @@ -10,21 +10,14 @@ namespace NATS.Server.Clustering.Tests.Routes; public class RouteRemoteSubCleanupParityBatch2Tests { [Fact] - public void Routed_sub_key_helpers_parse_account_and_queue_fields() + public void Routed_sub_key_exposes_route_account_subject_and_queue_fields() { - var key = SubList.BuildRoutedSubKey("R1", "A", "orders.*", "q1"); + var key = RoutedSubKey.FromRemoteSubscription(new RemoteSubscription("orders.*", "q1", "R1", "A")); - SubList.GetAccNameFromRoutedSubKey(key).ShouldBe("A"); - - var info = SubList.GetRoutedSubKeyInfo(key); - info.ShouldNotBeNull(); - info.Value.RouteId.ShouldBe("R1"); - info.Value.Account.ShouldBe("A"); - info.Value.Subject.ShouldBe("orders.*"); - info.Value.Queue.ShouldBe("q1"); - - SubList.GetRoutedSubKeyInfo("invalid").ShouldBeNull(); - SubList.GetAccNameFromRoutedSubKey("invalid").ShouldBeNull(); + key.RouteId.ShouldBe("R1"); + key.Account.ShouldBe("A"); + key.Subject.ShouldBe("orders.*"); + key.Queue.ShouldBe("q1"); } [Fact]