diff --git a/ackhandlernew/received_packet_history.go b/ackhandlernew/received_packet_history.go index e843668a4..608703da6 100644 --- a/ackhandlernew/received_packet_history.go +++ b/ackhandlernew/received_packet_history.go @@ -61,6 +61,22 @@ func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) { h.ranges.InsertBefore(utils.PacketInterval{Start: p, End: p}, h.ranges.Front()) } +func (h *receivedPacketHistory) DeleteBelow(leastUnacked protocol.PacketNumber) { + nextEl := h.ranges.Front() + for el := h.ranges.Front(); nextEl != nil; el = nextEl { + nextEl = el.Next() + + if leastUnacked > el.Value.Start && leastUnacked <= el.Value.End { + el.Value.Start = leastUnacked + } + if el.Value.End < leastUnacked { // delete a whole range + h.ranges.Remove(el) + } else { + return + } + } +} + // GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame func (h *receivedPacketHistory) GetAckRanges() []frames.AckRange { if h.ranges.Len() == 0 { diff --git a/ackhandlernew/received_packet_history_test.go b/ackhandlernew/received_packet_history_test.go index 5088e83dd..7f8f0ca07 100644 --- a/ackhandlernew/received_packet_history_test.go +++ b/ackhandlernew/received_packet_history_test.go @@ -121,6 +121,58 @@ var _ = Describe("receivedPacketHistory", func() { }) }) + Context("deleting", func() { + It("does nothing when the history is empty", func() { + hist.DeleteBelow(5) + Expect(hist.ranges.Len()).To(BeZero()) + }) + + It("deletes a range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(6) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("deletes multiple ranges", func() { + hist.ReceivedPacket(1) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(8) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("adjusts a range, if leastUnacked lies inside it", func() { + hist.ReceivedPacket(3) + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(6) + hist.DeleteBelow(4) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 6})) + }) + + It("adjusts a range, if leastUnacked is the last of the range", func() { + hist.ReceivedPacket(4) + hist.ReceivedPacket(5) + hist.ReceivedPacket(10) + hist.DeleteBelow(5) + Expect(hist.ranges.Len()).To(Equal(2)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 5, End: 5})) + Expect(hist.ranges.Back().Value).To(Equal(utils.PacketInterval{Start: 10, End: 10})) + }) + + It("keeps a one-packet range, if leastUnacked is exactly that value", func() { + hist.ReceivedPacket(4) + hist.DeleteBelow(4) + Expect(hist.ranges.Len()).To(Equal(1)) + Expect(hist.ranges.Front().Value).To(Equal(utils.PacketInterval{Start: 4, End: 4})) + }) + }) + Context("ACK range export", func() { It("returns nil if there are no ranges", func() { Expect(hist.GetAckRanges()).To(BeNil())