perf: reduce SubList token string churn

This commit is contained in:
Joseph Doherty
2026-03-13 09:53:37 -04:00
parent 348bec36b2
commit 5876ad7dfa
2 changed files with 31 additions and 4 deletions

View File

@@ -362,9 +362,9 @@ public sealed class SubList : IDisposable
} }
else else
{ {
var key = token.ToString(); if (!TryGetLiteralNode(level, token, out _, out node))
if (!level.Nodes.TryGetValue(key, out node))
{ {
var key = token.ToString();
node = new TrieNode(); node = new TrieNode();
level.Nodes[key] = node; level.Nodes[key] = node;
} }
@@ -474,13 +474,20 @@ public sealed class SubList : IDisposable
} }
else else
{ {
level.Nodes.TryGetValue(token.ToString(), out node); if (!TryGetLiteralNode(level, token, out var existingToken, out node))
return false;
pathList.Add((level, node, existingToken, isPwc: false, isFwc: false));
if (node.Next == null)
return false; // corrupted trie state
level = node.Next;
continue;
} }
if (node == null) if (node == null)
return false; // not found return false; // not found
var tokenStr = token.ToString(); var tokenStr = isPwc ? "*" : ">";
pathList.Add((level, node, tokenStr, isPwc, isFwc)); pathList.Add((level, node, tokenStr, isPwc, isFwc));
if (node.Next == null) if (node.Next == null)
return false; // corrupted trie state return false; // corrupted trie state
@@ -652,6 +659,23 @@ public sealed class SubList : IDisposable
return removed; return removed;
} }
private static bool TryGetLiteralNode(TrieLevel level, ReadOnlySpan<char> token, out string existingToken, out TrieNode node)
{
foreach (var (candidate, existingNode) in level.Nodes)
{
if (!SubjectMatch.TokenEquals(token, candidate))
continue;
existingToken = candidate;
node = existingNode;
return true;
}
existingToken = string.Empty;
node = null!;
return false;
}
private bool HasExactQueueInterestNoLock(string subject, string queue) private bool HasExactQueueInterestNoLock(string subject, string queue)
{ {
var subs = new List<Subscription>(); var subs = new List<Subscription>();

View File

@@ -249,6 +249,9 @@ public static class SubjectMatch
return tokens.Count == test.Count; return tokens.Count == test.Count;
} }
internal static bool TokenEquals(ReadOnlySpan<char> token, string candidate)
=> token.SequenceEqual(candidate);
private static bool TokensCanMatch(ReadOnlySpan<char> t1, ReadOnlySpan<char> t2) private static bool TokensCanMatch(ReadOnlySpan<char> t1, ReadOnlySpan<char> t2)
{ {
if (t1.Length == 1 && (t1[0] == Pwc || t1[0] == Fwc)) if (t1.Length == 1 && (t1[0] == Pwc || t1[0] == Fwc))