fix: address code quality review findings for batch 1
- SubjectsCollide: split tokens once upfront instead of O(n²) TokenAt calls - NatsHeaderParser: manual digit accumulation avoids string allocation and overflow - NatsHeaders: use IReadOnlyDictionary for Headers, immutable Invalid sentinel - PermissionLruCache: add missing Count property
This commit is contained in:
@@ -35,6 +35,17 @@ public sealed class PermissionLruCache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _map.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Set(string key, bool value)
|
public void Set(string key, bool value)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace NATS.Server.Protocol;
|
namespace NATS.Server.Protocol;
|
||||||
|
|
||||||
public readonly struct NatsHeaders
|
public readonly struct NatsHeaders()
|
||||||
{
|
{
|
||||||
public int Status { get; init; }
|
public int Status { get; init; }
|
||||||
public string Description { get; init; }
|
public string Description { get; init; } = string.Empty;
|
||||||
public Dictionary<string, string[]> Headers { get; init; }
|
public IReadOnlyDictionary<string, string[]> Headers { get; init; } = ReadOnlyDictionary<string, string[]>.Empty;
|
||||||
|
|
||||||
public static readonly NatsHeaders Invalid = new() { Status = -1, Description = string.Empty, Headers = new() };
|
public static readonly NatsHeaders Invalid = new()
|
||||||
|
{
|
||||||
|
Status = -1,
|
||||||
|
Description = string.Empty,
|
||||||
|
Headers = ReadOnlyDictionary<string, string[]>.Empty,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class NatsHeaderParser
|
public static class NatsHeaderParser
|
||||||
{
|
{
|
||||||
private static readonly byte[] CrLf = "\r\n"u8.ToArray();
|
private static ReadOnlySpan<byte> CrLf => "\r\n"u8;
|
||||||
private static readonly byte[] Prefix = "NATS/1.0"u8.ToArray();
|
private static ReadOnlySpan<byte> Prefix => "NATS/1.0"u8;
|
||||||
|
|
||||||
public static NatsHeaders Parse(ReadOnlySpan<byte> data)
|
public static NatsHeaders Parse(ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
@@ -46,9 +52,10 @@ public static class NatsHeaderParser
|
|||||||
while (si < statusLine.Length && statusLine[si] >= (byte)'0' && statusLine[si] <= (byte)'9')
|
while (si < statusLine.Length && statusLine[si] >= (byte)'0' && statusLine[si] <= (byte)'9')
|
||||||
si++;
|
si++;
|
||||||
|
|
||||||
if (si > numStart)
|
if (si > numStart && si - numStart <= 5) // max 5 digits to avoid overflow
|
||||||
{
|
{
|
||||||
status = int.Parse(Encoding.ASCII.GetString(statusLine[numStart..si]));
|
for (int idx = numStart; idx < si; idx++)
|
||||||
|
status = status * 10 + (statusLine[idx] - '0');
|
||||||
|
|
||||||
while (si < statusLine.Length && statusLine[si] == (byte)' ')
|
while (si < statusLine.Length && statusLine[si] == (byte)' ')
|
||||||
si++;
|
si++;
|
||||||
|
|||||||
@@ -172,11 +172,13 @@ public static class SubjectMatch
|
|||||||
if (lit2 && !lit1)
|
if (lit2 && !lit1)
|
||||||
return MatchLiteral(subj2, subj1);
|
return MatchLiteral(subj2, subj1);
|
||||||
|
|
||||||
// Both have wildcards
|
// Both have wildcards — split once to avoid O(n²) TokenAt calls
|
||||||
int n1 = NumTokens(subj1);
|
var tokens1 = subj1.Split(Sep);
|
||||||
int n2 = NumTokens(subj2);
|
var tokens2 = subj2.Split(Sep);
|
||||||
bool hasFwc1 = subj1.Contains('>');
|
int n1 = tokens1.Length;
|
||||||
bool hasFwc2 = subj2.Contains('>');
|
int n2 = tokens2.Length;
|
||||||
|
bool hasFwc1 = tokens1[^1] == ">";
|
||||||
|
bool hasFwc2 = tokens2[^1] == ">";
|
||||||
|
|
||||||
if (!hasFwc1 && !hasFwc2 && n1 != n2)
|
if (!hasFwc1 && !hasFwc2 && n1 != n2)
|
||||||
return false;
|
return false;
|
||||||
@@ -188,9 +190,7 @@ public static class SubjectMatch
|
|||||||
int stop = Math.Min(n1, n2);
|
int stop = Math.Min(n1, n2);
|
||||||
for (int i = 0; i < stop; i++)
|
for (int i = 0; i < stop; i++)
|
||||||
{
|
{
|
||||||
var t1 = TokenAt(subj1, i);
|
if (!TokensCanMatch(tokens1[i], tokens2[i]))
|
||||||
var t2 = TokenAt(subj2, i);
|
|
||||||
if (!TokensCanMatch(t1, t2))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user