perf: optimize fan-out hot path and switch benchmarks to Release build
Round 9 optimizations targeting per-delivery overhead: - Switch benchmark harness from Debug to Release build (biggest impact: durable fetch 0.42x→0.92x, request-reply to parity) - Batch server-wide stats after fan-out loop (2 Interlocked per delivery → 2 per publish) - Guard auto-unsub tracking with MaxMessages > 0 (skip Interlocked in common case) - Cache SID as ASCII bytes on Subscription (avoid per-delivery encoding) - Pre-encode subject bytes once before fan-out loop (avoid N encodings) - Add 1-element subject string cache in ProcessPub (avoid repeated alloc) - Remove Interlocked from SubList.Match stats counters (approximate is fine) - Extract WriteMessageToBuffer helper for both string and span overloads
This commit is contained in:
@@ -554,7 +554,7 @@ public sealed class SubList : IDisposable
|
||||
|
||||
public SubListResult Match(string subject)
|
||||
{
|
||||
Interlocked.Increment(ref _matches);
|
||||
_matches++;
|
||||
var currentGen = Interlocked.Read(ref _generation);
|
||||
|
||||
_lock.EnterReadLock();
|
||||
@@ -562,7 +562,7 @@ public sealed class SubList : IDisposable
|
||||
{
|
||||
if (_cache != null && _cache.TryGetValue(subject, out var cached) && cached.Generation == currentGen)
|
||||
{
|
||||
Interlocked.Increment(ref _cacheHits);
|
||||
_cacheHits++;
|
||||
return cached.Result;
|
||||
}
|
||||
}
|
||||
@@ -581,7 +581,7 @@ public sealed class SubList : IDisposable
|
||||
currentGen = Interlocked.Read(ref _generation);
|
||||
if (_cache != null && _cache.TryGetValue(subject, out var cached) && cached.Generation == currentGen)
|
||||
{
|
||||
Interlocked.Increment(ref _cacheHits);
|
||||
_cacheHits++;
|
||||
return cached.Result;
|
||||
}
|
||||
|
||||
@@ -940,8 +940,8 @@ public sealed class SubList : IDisposable
|
||||
_lock.ExitReadLock();
|
||||
}
|
||||
|
||||
var matches = Interlocked.Read(ref _matches);
|
||||
var cacheHits = Interlocked.Read(ref _cacheHits);
|
||||
var matches = Volatile.Read(ref _matches);
|
||||
var cacheHits = Volatile.Read(ref _cacheHits);
|
||||
var hitRate = matches > 0 ? (double)cacheHits / matches : 0.0;
|
||||
|
||||
uint maxFanout = 0;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Text;
|
||||
using NATS.Server;
|
||||
using NATS.Server.Imports;
|
||||
|
||||
@@ -5,9 +6,17 @@ namespace NATS.Server.Subscriptions;
|
||||
|
||||
public sealed class Subscription
|
||||
{
|
||||
private byte[]? _sidBytes;
|
||||
|
||||
public required string Subject { get; init; }
|
||||
public string? Queue { get; init; }
|
||||
public required string Sid { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Pre-encoded ASCII bytes of the SID, cached to avoid per-delivery encoding.
|
||||
/// </summary>
|
||||
public byte[] SidBytes => _sidBytes ??= Encoding.ASCII.GetBytes(Sid);
|
||||
|
||||
public long MessageCount; // Interlocked
|
||||
public long MaxMessages; // 0 = unlimited
|
||||
public INatsClient? Client { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user