refactor timer calculation in sesssion to reduce syscalls

This commit is contained in:
Lucas Clemente
2016-05-24 17:42:14 +02:00
parent 55fe1390b3
commit d4a189b2d1
6 changed files with 49 additions and 44 deletions

View File

@@ -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

View File

@@ -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
} }

View File

@@ -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())
}) })
}) })

View File

@@ -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{}

View File

@@ -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)

View File

@@ -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 {