forked from quic-go/quic-go
refactor timer calculation in sesssion to reduce syscalls
This commit is contained in:
@@ -21,7 +21,7 @@ type SentPacketHandler interface {
|
|||||||
CongestionAllowsSending() bool
|
CongestionAllowsSending() bool
|
||||||
CheckForError() error
|
CheckForError() error
|
||||||
|
|
||||||
TimeToFirstRTO() time.Duration
|
TimeOfFirstRTO() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
||||||
|
|||||||
@@ -313,17 +313,15 @@ func (h *sentPacketHandler) queuePacketsRTO() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHandler) TimeToFirstRTO() time.Duration {
|
func (h *sentPacketHandler) TimeOfFirstRTO() time.Time {
|
||||||
now := time.Now()
|
var min time.Time
|
||||||
min := utils.InfDuration
|
|
||||||
for _, p := range h.packetHistory {
|
for _, p := range h.packetHistory {
|
||||||
if p == nil || p.Retransmitted {
|
if p == nil || p.Retransmitted {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if now.After(p.rtoTime) {
|
if min.IsZero() || min.After(p.rtoTime) {
|
||||||
return 0
|
min = p.rtoTime
|
||||||
}
|
}
|
||||||
min = utils.MinDuration(min, p.rtoTime.Sub(now))
|
|
||||||
}
|
}
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -646,27 +646,20 @@ var _ = Describe("SentPacketHandler", func() {
|
|||||||
|
|
||||||
Context("RTO retransmission", func() {
|
Context("RTO retransmission", func() {
|
||||||
Context("calculating the time to first RTO", func() {
|
Context("calculating the time to first RTO", func() {
|
||||||
It("defaults to inf", func() {
|
It("defaults to zero", func() {
|
||||||
Expect(handler.TimeToFirstRTO()).To(Equal(utils.InfDuration))
|
Expect(handler.TimeOfFirstRTO().IsZero()).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns time to RTO", func() {
|
It("returns time to RTO", func() {
|
||||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(handler.TimeToFirstRTO()).To(BeNumerically("~", protocol.DefaultRetransmissionTime, time.Millisecond))
|
Expect(handler.TimeOfFirstRTO().Sub(time.Now())).To(BeNumerically("~", protocol.DefaultRetransmissionTime, time.Millisecond))
|
||||||
})
|
|
||||||
|
|
||||||
It("returns 0 when RTOs are required", func() {
|
|
||||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
handler.packetHistory[1].rtoTime = time.Now().Add(-time.Second)
|
|
||||||
Expect(handler.TimeToFirstRTO()).To(BeZero())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("ignores nil packets", func() {
|
It("ignores nil packets", func() {
|
||||||
handler.packetHistory[1] = nil
|
handler.packetHistory[1] = nil
|
||||||
handler.queuePacketsRTO()
|
handler.queuePacketsRTO()
|
||||||
Expect(handler.TimeToFirstRTO()).To(Equal(utils.InfDuration))
|
Expect(handler.TimeOfFirstRTO().IsZero()).To(BeTrue())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func (h *mockSentPacketHandler) BytesInFlight() protocol.ByteCount
|
|||||||
func (h *mockSentPacketHandler) GetLargestObserved() protocol.PacketNumber { return 1 }
|
func (h *mockSentPacketHandler) GetLargestObserved() protocol.PacketNumber { return 1 }
|
||||||
func (h *mockSentPacketHandler) CongestionAllowsSending() bool { panic("not implemented") }
|
func (h *mockSentPacketHandler) CongestionAllowsSending() bool { panic("not implemented") }
|
||||||
func (h *mockSentPacketHandler) CheckForError() error { panic("not implemented") }
|
func (h *mockSentPacketHandler) CheckForError() error { panic("not implemented") }
|
||||||
func (h *mockSentPacketHandler) TimeToFirstRTO() time.Duration { panic("not implemented") }
|
func (h *mockSentPacketHandler) TimeOfFirstRTO() time.Time { panic("not implemented") }
|
||||||
|
|
||||||
func newMockSentPacketHandler() ackhandler.SentPacketHandler {
|
func newMockSentPacketHandler() ackhandler.SentPacketHandler {
|
||||||
return &mockSentPacketHandler{}
|
return &mockSentPacketHandler{}
|
||||||
|
|||||||
56
session.go
56
session.go
@@ -78,8 +78,9 @@ type Session struct {
|
|||||||
|
|
||||||
lastNetworkActivityTime time.Time
|
lastNetworkActivityTime time.Time
|
||||||
|
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
timerRead bool
|
currentDeadline time.Time
|
||||||
|
timerRead bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSession makes a new session
|
// newSession makes a new session
|
||||||
@@ -139,29 +140,7 @@ func (s *Session) run() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the minimum of all timeouts
|
s.maybeResetTimer()
|
||||||
now := time.Now()
|
|
||||||
firstTimeout := utils.InfDuration
|
|
||||||
// Some timeouts are only set when we can actually send
|
|
||||||
// Note: if a packet arrives, we go through this again afterwards.
|
|
||||||
if s.sentPacketHandler.CongestionAllowsSending() {
|
|
||||||
// Small packet send delay
|
|
||||||
if !s.smallPacketDelayedOccurranceTime.IsZero() {
|
|
||||||
firstTimeout = utils.MinDuration(firstTimeout, s.smallPacketDelayedOccurranceTime.Add(protocol.SmallPacketSendDelay).Sub(now))
|
|
||||||
}
|
|
||||||
// RTOs
|
|
||||||
firstTimeout = utils.MinDuration(firstTimeout, s.sentPacketHandler.TimeToFirstRTO())
|
|
||||||
}
|
|
||||||
// Idle connection timeout
|
|
||||||
firstTimeout = utils.MinDuration(firstTimeout, s.lastNetworkActivityTime.Add(s.connectionParametersManager.GetIdleConnectionStateLifetime()).Sub(now))
|
|
||||||
|
|
||||||
// We need to drain the timer if the value from its channel was not read yet.
|
|
||||||
// See https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVPoU
|
|
||||||
if !s.timer.Stop() && !s.timerRead {
|
|
||||||
<-s.timer.C
|
|
||||||
}
|
|
||||||
s.timer.Reset(firstTimeout)
|
|
||||||
s.timerRead = false
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
select {
|
select {
|
||||||
@@ -208,6 +187,33 @@ func (s *Session) run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) maybeResetTimer() {
|
||||||
|
nextDeadline := s.lastNetworkActivityTime.Add(s.connectionParametersManager.GetIdleConnectionStateLifetime())
|
||||||
|
|
||||||
|
if !s.smallPacketDelayedOccurranceTime.IsZero() {
|
||||||
|
// nextDeadline = utils.MinDuration(firstTimeout, s.smallPacketDelayedOccurranceTime.Add(protocol.SmallPacketSendDelay).Sub(now))
|
||||||
|
nextDeadline = utils.MinTime(nextDeadline, s.smallPacketDelayedOccurranceTime.Add(protocol.SmallPacketSendDelay))
|
||||||
|
}
|
||||||
|
if rtoTime := s.sentPacketHandler.TimeOfFirstRTO(); !rtoTime.IsZero() {
|
||||||
|
nextDeadline = utils.MinTime(nextDeadline, rtoTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextDeadline.Equal(s.currentDeadline) {
|
||||||
|
// No need to reset the timer
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to drain the timer if the value from its channel was not read yet.
|
||||||
|
// See https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVPoU
|
||||||
|
if !s.timer.Stop() && !s.timerRead {
|
||||||
|
<-s.timer.C
|
||||||
|
}
|
||||||
|
s.timer.Reset(nextDeadline.Sub(time.Now()))
|
||||||
|
|
||||||
|
s.timerRead = false
|
||||||
|
s.currentDeadline = nextDeadline
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) handlePacketImpl(remoteAddr interface{}, hdr *publicHeader, data []byte) error {
|
func (s *Session) handlePacketImpl(remoteAddr interface{}, hdr *publicHeader, data []byte) error {
|
||||||
s.lastNetworkActivityTime = time.Now()
|
s.lastNetworkActivityTime = time.Now()
|
||||||
r := bytes.NewReader(data)
|
r := bytes.NewReader(data)
|
||||||
|
|||||||
@@ -98,6 +98,14 @@ func AbsDuration(d time.Duration) time.Duration {
|
|||||||
return -d
|
return -d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MinTime returns the earlier time
|
||||||
|
func MinTime(a, b time.Time) time.Time {
|
||||||
|
if a.After(b) {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
// MaxPacketNumber returns the max packet number
|
// MaxPacketNumber returns the max packet number
|
||||||
func MaxPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber {
|
func MaxPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber {
|
||||||
if a > b {
|
if a > b {
|
||||||
|
|||||||
Reference in New Issue
Block a user