fix: prevent QUIC heartbeat stalls and isolate TCP retransmission counters [CI] [SKIP TESTS]
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful

This commit is contained in:
justme committed 2026-10-20 18:23:31 +08:00
1 parent 0066a947da
commit 0fd38b2367
14 files changed
+299 -50

No files matched your search

@@ -211,6 +211,55 @@ public sealed class OpTests
Assert.Equal(100UL, retrans.Denominator);
}
[Fact]
public void Retrans_InterleavedConnections_DoNotCreateFalseRetransmissions()
{
long ts = ChunkFactory.ProbeUs(0);
var builder = new StreamBuilder(Kinds.TcpEcho.FindStream("tcp_info")!);
builder.Add(ts, 0, 40_000, 0, 10, 10, 1000, 0, 1);
builder.Add(ts + 1_000_000, 0, 40_000, 0, 10, 20, 1100, 0, 2);
builder.Add(ts + 2_000_000, 0, 40_000, 0, 10, 11, 1100, 0, 1);
builder.Add(ts + 3_000_000, 0, 40_000, 0, 10, 21, 1200, 0, 2);
RawChunk chunk = ChunkFactory.Echo(s_agent, "tcp_echo", T0, 10, 100,
_ => new EchoPacket(false, false, 20_000, 20_000), extraStreams: [builder.Build()]);
var retrans = (RatioAcc)EvaluateOneBucket(chunk, "tcp.retrans").Items["tcp.retrans"];
Assert.Equal(2UL, retrans.Numerator);
Assert.Equal(200UL, retrans.Denominator);
}
[Fact]
public void Retrans_OutOfOrderSamples_DoNotMoveTheBaselineBackwards()
{
long ts = ChunkFactory.ProbeUs(0);
RawStream info = ChunkFactory.TcpInfo([
(ts, 0, 40_000u, 0u, 100u),
(ts + 2_000_000, 0, 40_000u, 2u, 300u),
(ts + 1_000_000, 0, 40_000u, 1u, 200u),
(ts + 3_000_000, 0, 40_000u, 3u, 400u),
]);
RawChunk chunk = ChunkFactory.Echo(s_agent, "tcp_echo", T0, 10, 100,
_ => new EchoPacket(false, false, 20_000, 20_000), extraStreams: [info]);
var retrans = (RatioAcc)EvaluateOneBucket(chunk, "tcp.retrans").Items["tcp.retrans"];
Assert.Equal(3UL, retrans.Numerator);
Assert.Equal(300UL, retrans.Denominator);
}
[Fact]
public void Retrans_EqualConnectionIdsOnDifferentSides_AreIndependent()
{
long ts = ChunkFactory.ProbeUs(0);
var builder = new StreamBuilder(Kinds.TcpEcho.FindStream("tcp_info")!);
builder.Add(ts, 0, 40_000, 0, 10, 10, 1000, 0, 1);
builder.Add(ts, 1, 40_000, 0, 10, 100, 2000, 0, 1);
builder.Add(ts + 1_000_000, 0, 40_000, 0, 10, 11, 1100, 0, 1);
builder.Add(ts + 1_000_000, 1, 40_000, 0, 10, 102, 2200, 0, 1);
RawChunk chunk = ChunkFactory.Echo(s_agent, "tcp_echo", T0, 10, 100,
_ => new EchoPacket(false, false, 20_000, 20_000), extraStreams: [builder.Build()]);
var retrans = (RatioAcc)EvaluateOneBucket(chunk, "tcp.retrans").Items["tcp.retrans"];
Assert.Equal(3UL, retrans.Numerator);
Assert.Equal(300UL, retrans.Denominator);
}
[Fact]
public void Connect_Outcomes_AreCountedByClass()
{
@@ -274,6 +274,11 @@ public sealed class AgentSimulator : IAsyncDisposable
{
// 已经断开
}
catch (OperationCanceledException) when (_stop.IsCancellationRequested)
{
// Canceling the receive loop may abort/dispose the transport
// between the State check and CloseOutputAsync.
}
}
if (_loop is not null)
@@ -79,7 +79,7 @@ public static class ChunkFactory
var builder = new StreamBuilder(Kinds.TcpEcho.FindStream("tcp_info")!);
foreach ((long ts, byte side, uint srtt, uint retrans, uint segs) in samples)
{
builder.Add(ts, side, srtt, srtt / 4, 10, retrans, segs, segs * 100L);
builder.Add(ts, side, srtt, srtt / 4, 10, retrans, segs, segs * 100L, null);
}
return builder.Build();