forked from quic-go/quic-go
ackhandler: store the last four skipped packets (#5322)
This allows for more accurate packet number difference calculations, which is especially important once we attempt to detect spurious loss detection events.
This commit is contained in:
@@ -3,10 +3,13 @@ package ackhandler
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
"iter"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxSkippedPackets = 4
|
||||||
|
|
||||||
type sentPacketHistory struct {
|
type sentPacketHistory struct {
|
||||||
packets []*packet
|
packets []*packet
|
||||||
pathProbePackets []packetWithPacketNumber
|
pathProbePackets []packetWithPacketNumber
|
||||||
@@ -25,6 +28,7 @@ func newSentPacketHistory(isAppData bool) *sentPacketHistory {
|
|||||||
}
|
}
|
||||||
if isAppData {
|
if isAppData {
|
||||||
h.packets = make([]*packet, 0, 32)
|
h.packets = make([]*packet, 0, 32)
|
||||||
|
h.skippedPackets = make([]protocol.PacketNumber, 0, maxSkippedPackets)
|
||||||
} else {
|
} else {
|
||||||
h.packets = make([]*packet, 0, 6)
|
h.packets = make([]*packet, 0, 6)
|
||||||
}
|
}
|
||||||
@@ -48,6 +52,9 @@ func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
|||||||
if len(h.packets) > 0 {
|
if len(h.packets) > 0 {
|
||||||
h.packets = append(h.packets, nil)
|
h.packets = append(h.packets, nil)
|
||||||
}
|
}
|
||||||
|
if len(h.skippedPackets) == maxSkippedPackets {
|
||||||
|
h.skippedPackets = slices.Delete(h.skippedPackets, 0, 1)
|
||||||
|
}
|
||||||
h.skippedPackets = append(h.skippedPackets, pn)
|
h.skippedPackets = append(h.skippedPackets, pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,13 +170,6 @@ func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
|
|||||||
if len(h.packets) > 0 && h.packets[0] == nil {
|
if len(h.packets) > 0 && h.packets[0] == nil {
|
||||||
panic("cleanup failed")
|
panic("cleanup failed")
|
||||||
}
|
}
|
||||||
if len(h.packets) > 0 && len(h.skippedPackets) > 0 {
|
|
||||||
for _, p := range h.skippedPackets {
|
|
||||||
if p < h.firstPacketNumber {
|
|
||||||
h.skippedPackets = h.skippedPackets[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ func TestSentPacketHistoryRemovePackets(t *testing.T) {
|
|||||||
require.Equal(t, []protocol.PacketNumber{2, 3, 5}, slices.Collect(hist.SkippedPackets()))
|
require.Equal(t, []protocol.PacketNumber{2, 3, 5}, slices.Collect(hist.SkippedPackets()))
|
||||||
require.NoError(t, hist.Remove(1))
|
require.NoError(t, hist.Remove(1))
|
||||||
require.Equal(t, []protocol.PacketNumber{4, 6}, hist.getPacketNumbers())
|
require.Equal(t, []protocol.PacketNumber{4, 6}, hist.getPacketNumbers())
|
||||||
require.Equal(t, []protocol.PacketNumber{5}, slices.Collect(hist.SkippedPackets()))
|
// skipped packets should be preserved
|
||||||
|
require.Equal(t, []protocol.PacketNumber{2, 3, 5}, slices.Collect(hist.SkippedPackets()))
|
||||||
|
|
||||||
// add one more packet
|
// add one more packet
|
||||||
hist.SentAckElicitingPacket(7, &packet{})
|
hist.SentAckElicitingPacket(7, &packet{})
|
||||||
@@ -114,12 +115,20 @@ func TestSentPacketHistoryRemovePackets(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.EqualError(t, err, "packet 9 not found in sent packet history")
|
require.EqualError(t, err, "packet 9 not found in sent packet history")
|
||||||
|
|
||||||
|
// only the last 4 skipped packets should be preserved
|
||||||
|
hist.SkippedPacket(9)
|
||||||
|
hist.SkippedPacket(10)
|
||||||
|
hist.SentAckElicitingPacket(11, &packet{})
|
||||||
|
hist.SkippedPacket(12)
|
||||||
|
require.Equal(t, []protocol.PacketNumber{5, 9, 10, 12}, slices.Collect(hist.SkippedPackets()))
|
||||||
|
|
||||||
// Remove all packets
|
// Remove all packets
|
||||||
require.NoError(t, hist.Remove(4))
|
require.NoError(t, hist.Remove(4))
|
||||||
require.NoError(t, hist.Remove(6))
|
require.NoError(t, hist.Remove(6))
|
||||||
require.NoError(t, hist.Remove(8))
|
require.NoError(t, hist.Remove(8))
|
||||||
|
require.NoError(t, hist.Remove(11))
|
||||||
require.Empty(t, hist.getPacketNumbers())
|
require.Empty(t, hist.getPacketNumbers())
|
||||||
require.Empty(t, slices.Collect(hist.SkippedPackets()))
|
require.Len(t, slices.Collect(hist.SkippedPackets()), 4)
|
||||||
require.False(t, hist.HasOutstandingPackets())
|
require.False(t, hist.HasOutstandingPackets())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +180,7 @@ func TestSentPacketHistoryIterating(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, []protocol.PacketNumber{1, 2, 6}, packets)
|
require.Equal(t, []protocol.PacketNumber{1, 2, 6}, packets)
|
||||||
require.Equal(t, []protocol.PacketNumber{4, 5}, slices.Collect(hist.SkippedPackets()))
|
require.Equal(t, []protocol.PacketNumber{0, 4, 5}, slices.Collect(hist.SkippedPackets()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSentPacketHistoryDeleteWhileIterating(t *testing.T) {
|
func TestSentPacketHistoryDeleteWhileIterating(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user