From 73856f6778e2316c8d0bcf3f741e1fa9f815e0cc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 15:14:56 +0000 Subject: [PATCH] fix(quic-interop): bump initial flow-control windows to 32MB for longrtt The longrtt testcase failed at 8s with only 1.2 KB received (out of 3 MB requested). Trace from inspect-testcase: handshake completed at t=4502 (3 RTTs at 750ms one-way as expected) first stream byte arrived at t=4694, ~200ms after test killed at t=8s with code=0x0 (graceful close from us) After handshake, ~3.5s of transfer time was available before the docker-compose timeout. With our default initialMaxStreamDataBidiLocal = 1 MB, the peer sends 1 MB then stalls until our parser fires a MAX_STREAM_DATA bump. At 1.5s RTT each stall is one round-trip lost (~1.5s). For a 3 MB file that's 2 stalls = 3s of pure flow-control idle on top of CC slow-start. Setting initialMaxData and initialMaxStreamData{BidiLocal, BidiRemote,Uni} to 32 MB removes flow control as a bottleneck for the largest interop transfers (longrtt 5 MB, transfercorruption few MB) and lets the peer's congestion control alone drive the rate. Doesn't help handshake duration (which is RTT-bound and correct). Doesn't help slow-start ramp (CC, server-side). Should still close the gap on longrtt. --- .../quic/interop/runner/InteropClient.kt | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt b/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt index 12ed601d6..30759e9e5 100644 --- a/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt +++ b/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt @@ -285,7 +285,25 @@ private fun runTransferTest( val conn = QuicConnection( serverName = host, - config = QuicConnectionConfig(), + config = + QuicConnectionConfig( + // Interop stress sizes — push the receive + // window past the largest single-file transfer + // any testcase exercises (longrtt does 5 MB, + // transferloss / transfercorruption do up to + // a few MB). Without this, the peer sends + // up to initialMaxStreamDataBidiLocal then + // stalls until our parser sends a + // MAX_STREAM_DATA — at high RTT (longrtt + // is 750 ms one-way) each stall is ~1.5 s + // round-trip lost. Setting both connection- + // and stream-level windows to 32 MB lets + // the peer's CC alone determine throughput. + initialMaxData = 32L * 1024 * 1024, + initialMaxStreamDataBidiLocal = 32L * 1024 * 1024, + initialMaxStreamDataBidiRemote = 32L * 1024 * 1024, + initialMaxStreamDataUni = 32L * 1024 * 1024, + ), tlsCertificateValidator = PermissiveCertificateValidator(), alpnList = offeredAlpns.map { it.wireBytes }, initialVersion = initialVersion,