perf(gateway): pool+coalesce worker pipe frame I/O (GWC-08, IPC-13, IPC-14)

Gateway server-side named-pipe frame path, wire format byte-identical:
- Writer (GWC-08/IPC-13): serialize once into a single ArrayPool-rented buffer
  holding the 4-byte LE length prefix + payload, then one WriteAsync. Removes
  the second serialization pass (ToByteArray re-ran CalculateSize), the
  separate prefix array + second stream write, and per-frame heap allocation.
- Reader (IPC-14): rent the payload buffer from ArrayPool instead of new byte[]
  per frame; read/parse bounded to the real length, return in finally. Matches
  the worker side which already pools.
- Correctness: length tracked separately from (larger) pool capacity; every
  rented buffer returned exactly once in finally incl. the malformed-protobuf
  path; ParseFrom copies into the message so the envelope never aliases the
  returned buffer.

Cross-checked LE-prefix framing agrees across gateway+worker writer/reader.
Server build clean (0 warnings); WorkerFrameProtocol tests 10/10 incl. a new
large-payload-near-cap round-trip (forces pool buffer > frame). The 2 failing
WorkerClient/FakeWorkerHarness tests are the known macOS UDS 104-char path
limit, not a regression.

Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
This commit is contained in:
Joseph Doherty
2026-07-09 14:58:09 -04:00
parent 34aede6767
commit baae59ce3b
3 changed files with 70 additions and 13 deletions
@@ -29,6 +29,32 @@ public sealed class WorkerFrameProtocolTests
Assert.Equal(original, parsed);
}
/// <summary>Verifies that a large payload near the message cap round-trips through the pooled write/read path.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task WriteAndReadAsync_WithLargePayloadNearMax_RoundTripsFrame()
{
// A payload comfortably larger than an ArrayPool bucket boundary so the rented buffer is
// larger than the exact frame length, exercising the length-bounded read and parse.
const int maxMessageBytes = 1024 * 1024;
WorkerFrameProtocolOptions options =
new(SessionId, GatewayContractInfo.WorkerProtocolVersion, maxMessageBytes);
await using MemoryStream stream = new();
WorkerEnvelope original = CreateEnvelope();
original.WorkerHello.WorkerVersion = new string('x', maxMessageBytes - 4096);
Assert.InRange(original.CalculateSize(), 1, maxMessageBytes);
WorkerFrameWriter writer = new(stream, options);
await writer.WriteAsync(original);
stream.Position = 0;
WorkerFrameReader reader = new(stream, options);
WorkerEnvelope parsed = await reader.ReadAsync();
Assert.Equal(original, parsed);
}
/// <summary>Verifies that reading a frame with partial reads reassembles the frame correctly.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]