use early retransmit in every packet number space

This commit is contained in:
Marten Seemann
2019-07-25 17:51:45 -04:00
parent f150ed4d4e
commit 91e57fe6c9
2 changed files with 58 additions and 26 deletions

View File

@@ -24,6 +24,7 @@ type packetNumberSpace struct {
history *sentPacketHistory
pns *packetNumberGenerator
lossTime time.Time
largestAcked protocol.PacketNumber
largestSent protocol.PacketNumber
}
@@ -68,9 +69,6 @@ type sentPacketHandler struct {
// Only applies to the application-data packet number space.
numProbesToSend int
// The time at which the next packet will be considered lost based on early transmit or exceeding the reordering window in time.
lossTime time.Time
// The alarm timeout
alarm time.Time
@@ -314,6 +312,25 @@ func (h *sentPacketHandler) determineNewlyAckedPackets(
return ackedPackets, err
}
func (h *sentPacketHandler) getEarliestLossTime() (time.Time, protocol.EncryptionLevel) {
var encLevel protocol.EncryptionLevel
var lossTime time.Time
if h.initialPackets != nil {
lossTime = h.initialPackets.lossTime
encLevel = protocol.EncryptionInitial
}
if h.handshakePackets != nil && (lossTime.IsZero() || h.handshakePackets.lossTime.Before(lossTime)) {
lossTime = h.handshakePackets.lossTime
encLevel = protocol.EncryptionHandshake
}
if lossTime.IsZero() || h.oneRTTPackets.lossTime.Before(lossTime) {
lossTime = h.oneRTTPackets.lossTime
encLevel = protocol.Encryption1RTT
}
return lossTime, encLevel
}
func (h *sentPacketHandler) hasOutstandingCryptoPackets() bool {
var hasInitial, hasHandshake bool
if h.initialPackets != nil {
@@ -336,11 +353,13 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
return
}
lossTime, _ := h.getEarliestLossTime()
if h.hasOutstandingCryptoPackets() {
h.alarm = h.lastSentCryptoPacketTime.Add(h.computeCryptoTimeout())
} else if !h.lossTime.IsZero() {
} else if !lossTime.IsZero() {
// Early retransmit timer or time loss detection.
h.alarm = h.lossTime
h.alarm = lossTime
} else { // PTO alarm
h.alarm = h.lastSentAckElicitingPacketTime.Add(h.rttStats.PTO() << h.ptoCount)
}
@@ -351,10 +370,8 @@ func (h *sentPacketHandler) detectLostPackets(
encLevel protocol.EncryptionLevel,
priorInFlight protocol.ByteCount,
) error {
if encLevel == protocol.Encryption1RTT {
h.lossTime = time.Time{}
}
pnSpace := h.getPacketNumberSpace(encLevel)
pnSpace.lossTime = time.Time{}
maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT()))
lossDelay := time.Duration(timeThreshold * maxRTT)
@@ -371,12 +388,12 @@ func (h *sentPacketHandler) detectLostPackets(
timeSinceSent := now.Sub(packet.SendTime)
if timeSinceSent > lossDelay {
lostPackets = append(lostPackets, packet)
} else if h.lossTime.IsZero() && encLevel == protocol.Encryption1RTT {
} else if pnSpace.lossTime.IsZero() && encLevel == protocol.Encryption1RTT {
if h.logger.Debug() {
h.logger.Debugf("\tsetting loss timer for packet %#x to %s (in %s)", packet.PacketNumber, lossDelay, lossDelay-timeSinceSent)
}
// Note: This conditional is only entered once per call
h.lossTime = now.Add(lossDelay - timeSinceSent)
pnSpace.lossTime = now.Add(lossDelay - timeSinceSent)
}
return true, nil
})
@@ -433,18 +450,19 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
func (h *sentPacketHandler) onVerifiedLossDetectionTimeout() error {
var err error
if h.hasOutstandingCryptoPackets() {
lossTime, encLevel := h.getEarliestLossTime()
if !lossTime.IsZero() {
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", lossTime)
}
// Early retransmit or time loss detection
err = h.detectLostPackets(time.Now(), encLevel, h.bytesInFlight)
} else if h.hasOutstandingCryptoPackets() {
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm fired in crypto mode. Crypto count: %d", h.cryptoCount)
}
h.cryptoCount++
err = h.queueCryptoPacketsForRetransmission()
} else if !h.lossTime.IsZero() {
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", h.lossTime)
}
// Early retransmit or time loss detection
err = h.detectLostPackets(time.Now(), protocol.Encryption1RTT, h.bytesInFlight)
} else { // PTO
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm fired in PTO mode. PTO count: %d", h.ptoCount)

View File

@@ -655,7 +655,7 @@ var _ = Describe("SentPacketHandler", func() {
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2}))
updateRTT(time.Hour)
Expect(handler.lossTime.IsZero()).To(BeTrue())
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
handler.OnLossDetectionTimeout() // TLP
handler.OnLossDetectionTimeout() // TLP
@@ -761,15 +761,29 @@ var _ = Describe("SentPacketHandler", func() {
now := time.Now()
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: now.Add(-time.Hour)}))
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2, SendTime: now.Add(-time.Second)}))
Expect(handler.lossTime.IsZero()).To(BeTrue())
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, now)
Expect(err).NotTo(HaveOccurred())
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, now)).To(Succeed())
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
// no need to set an alarm, since packet 1 was already declared lost
Expect(handler.lossTime.IsZero()).To(BeTrue())
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
Expect(handler.bytesInFlight).To(BeZero())
})
It("uses early retransmit for crypto packets", func() {
now := time.Now()
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 1, SendTime: now.Add(-time.Hour)}))
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 2, SendTime: now.Add(-time.Second)}))
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
Expect(handler.ReceivedAck(ack, 1, protocol.EncryptionInitial, now)).To(Succeed())
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
// no need to set an alarm, since packet 1 was already declared lost
Expect(handler.initialPackets.lossTime.IsZero()).To(BeTrue())
Expect(handler.bytesInFlight).To(BeZero())
})
@@ -778,15 +792,15 @@ var _ = Describe("SentPacketHandler", func() {
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: now.Add(-2 * time.Second), EncryptionLevel: protocol.Encryption1RTT}))
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2, SendTime: now.Add(-2 * time.Second), EncryptionLevel: protocol.Encryption1RTT}))
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 3, SendTime: now.Add(-time.Second), EncryptionLevel: protocol.Encryption1RTT}))
Expect(handler.lossTime.IsZero()).To(BeTrue())
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, now.Add(-time.Second))).To(Succeed())
Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Second))
// Packet 1 should be considered lost (1+1/8) RTTs after it was sent.
Expect(handler.lossTime.IsZero()).To(BeFalse())
Expect(handler.lossTime.Sub(getPacket(1, protocol.Encryption1RTT).SendTime)).To(Equal(time.Second * 9 / 8))
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeFalse())
Expect(handler.oneRTTPackets.lossTime.Sub(getPacket(1, protocol.Encryption1RTT).SendTime)).To(Equal(time.Second * 9 / 8))
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil())
@@ -810,7 +824,7 @@ var _ = Describe("SentPacketHandler", func() {
Expect(handler.ReceivedAck(ack, 1, protocol.EncryptionInitial, now)).To(Succeed())
// RTT is now 1 minute
Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Minute))
Expect(handler.lossTime.IsZero()).To(BeTrue())
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
Expect(handler.GetLossDetectionTimeout().Sub(sendTime)).To(Equal(2 * time.Minute))
Expect(handler.OnLossDetectionTimeout()).To(Succeed())