Merge branch 'opt/js-async-file-publish'

JetStream async file publish optimization (~10% improvement):
- Cached state properties eliminate GetStateAsync on publish path
- Single stream lookup eliminates double FindBySubject
- Removed _messageIndexes dictionary from write path
- Hand-rolled UTF-8 pub-ack formatter for success path
- Exponential flush backoff matching Go server
- Lazy StoredMessage materialization (MessageMeta struct)

# Conflicts:
#	benchmarks_comparison.md
This commit is contained in:
Joseph Doherty
2026-03-13 15:37:11 -04:00
9 changed files with 472 additions and 267 deletions

View File

@@ -1399,8 +1399,19 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
// Go reference: server/jetstream.go — jsPubAckResponse sent to reply.
if (replyTo != null)
{
var ackData = JsonSerializer.SerializeToUtf8Bytes(pubAck, s_jetStreamJsonOptions);
ProcessMessage(replyTo, null, default, ackData, sender);
if (JetStream.Publish.JetStreamPubAckFormatter.IsSimpleSuccess(pubAck))
{
// Fast path: hand-rolled UTF-8 formatter avoids JsonSerializer overhead.
Span<byte> ackBuf = stackalloc byte[256];
var ackLen = JetStream.Publish.JetStreamPubAckFormatter.FormatSuccess(ackBuf, pubAck.Stream, pubAck.Seq);
ProcessMessage(replyTo, null, default, ackBuf[..ackLen].ToArray(), sender);
}
else
{
var ackData = JsonSerializer.SerializeToUtf8Bytes(pubAck, s_jetStreamJsonOptions);
ProcessMessage(replyTo, null, default, ackData, sender);
}
return;
}
}