feat: add consecutive short-read counter to prevent buffer oscillation (Gap 5.10)

Require 4 consecutive short reads before shrinking AdaptiveReadBuffer, matching
the Go server's readLoop behaviour and preventing buffer size thrashing.
This commit is contained in:
Joseph Doherty
2026-02-25 11:36:12 -05:00
parent bd2504c8df
commit 18f0ca0587
2 changed files with 152 additions and 1 deletions

View File

@@ -1,19 +1,44 @@
namespace NATS.Server.IO;
/// <summary>
/// Dynamically sized read buffer that grows on full reads and shrinks
/// only after consecutive short reads exceed a threshold.
/// Go reference: server/client.go — readLoop buffer sizing with short-read counter.
/// </summary>
public sealed class AdaptiveReadBuffer
{
private const int ShortReadThreshold = 4;
private int _target = 4096;
private int _consecutiveShortReads;
public int CurrentSize => Math.Clamp(_target, 512, 64 * 1024);
/// <summary>Number of consecutive short reads since last full read or grow.</summary>
public int ConsecutiveShortReads => _consecutiveShortReads;
public void RecordRead(int bytesRead)
{
if (bytesRead <= 0)
return;
if (bytesRead >= _target)
{
_target = Math.Min(_target * 2, 64 * 1024);
_consecutiveShortReads = 0; // Reset on grow
}
else if (bytesRead < _target / 4)
_target = Math.Max(_target / 2, 512);
{
_consecutiveShortReads++;
if (_consecutiveShortReads >= ShortReadThreshold)
{
_target = Math.Max(_target / 2, 512);
_consecutiveShortReads = 0; // Reset after shrink
}
}
else
{
// Medium read — not short, not full. Reset counter.
_consecutiveShortReads = 0;
}
}
}