implement RTO computation in sentPacketHandler

ref #56
This commit is contained in:
Lucas Clemente
2016-05-18 20:34:07 +02:00
parent a0228a9049
commit 753f219638
6 changed files with 51 additions and 3 deletions

View File

@@ -19,6 +19,7 @@ type Packet struct {
Retransmitted bool // has this Packet ever been retransmitted
sendTime time.Time
rtoTime time.Time
}
// GetStreamFramesForRetransmission gets all the streamframes for retransmission

View File

@@ -118,7 +118,9 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) error {
if h.lastSentPacketNumber+1 != packet.PacketNumber {
return errWrongPacketNumberIncrement
}
packet.sendTime = time.Now()
now := time.Now()
packet.sendTime = now
packet.rtoTime = now.Add(h.getRTO())
if packet.Length == 0 {
return errors.New("SentPacketHandler: packet cannot be empty")
}
@@ -278,3 +280,11 @@ func (h *sentPacketHandler) GetLargestObserved() protocol.PacketNumber {
func (h *sentPacketHandler) AllowsSending() bool {
return h.BytesInFlight() <= h.congestion.GetCongestionWindow()
}
func (h *sentPacketHandler) getRTO() time.Duration {
rto := h.congestion.RetransmissionDelay()
if rto == 0 {
rto = protocol.DefaultRetransmissionTime
}
return utils.MaxDuration(rto, protocol.MinRetransmissionTime)
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/lucas-clemente/quic-go/congestion"
"github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@@ -39,9 +40,12 @@ func (m *mockCongestion) OnCongestionEvent(rttUpdated bool, bytesInFlight protoc
func (m *mockCongestion) SetNumEmulatedConnections(n int) { panic("not implemented") }
func (m *mockCongestion) OnRetransmissionTimeout(packetsRetransmitted bool) { panic("not implemented") }
func (m *mockCongestion) OnConnectionMigration() { panic("not implemented") }
func (m *mockCongestion) RetransmissionDelay() time.Duration { panic("not implemented") }
func (m *mockCongestion) SetSlowStartLargeReduction(enabled bool) { panic("not implemented") }
func (m *mockCongestion) RetransmissionDelay() time.Duration {
return protocol.DefaultRetransmissionTime
}
var _ = Describe("SentPacketHandler", func() {
var (
handler *sentPacketHandler
@@ -553,4 +557,30 @@ var _ = Describe("SentPacketHandler", func() {
Expect(handler.AllowsSending()).To(BeFalse())
})
})
Context("calculating RTO", func() {
It("uses default RTO", func() {
Expect(handler.getRTO()).To(Equal(protocol.DefaultRetransmissionTime))
})
It("uses RTO from rttStats", func() {
rtt := time.Second
expected := rtt + rtt/2*4
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
Expect(handler.getRTO()).To(Equal(expected))
})
It("limits RTO min", func() {
rtt := time.Millisecond
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
Expect(handler.getRTO()).To(Equal(protocol.MinRetransmissionTime))
})
It("stores RTO in sent packets", func() {
handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
val := handler.packetHistory[1].rtoTime
expected := time.Now().Add(protocol.DefaultRetransmissionTime)
Expect(utils.AbsDuration(expected.Sub(val))).To(BeNumerically("<", time.Millisecond))
})
})
})

View File

@@ -100,7 +100,7 @@ func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration, now time.Time) {
// Correct for ackDelay if information received from the peer results in a
// positive RTT sample. Otherwise, we use the sendDelta as a reasonable
// measure for smoothedRTT.
sample := (sendDelta)
sample := sendDelta
if sample > ackDelay {
sample -= ackDelay
}

View File

@@ -48,3 +48,9 @@ const InitialConnectionFlowControlWindow ByteCount = (1 << 14) // 16 kB
// InitialIdleConnectionStateLifetime is the initial idle connection state lifetime
const InitialIdleConnectionStateLifetime = 30 * time.Second
// DefaultRetransmissionTime is the RTO time on new connections
const DefaultRetransmissionTime = 500 * time.Millisecond
// MinRetransmissionTime is the minimum RTO time
const MinRetransmissionTime = 200 * time.Millisecond

View File

@@ -374,6 +374,7 @@ func (s *Session) closeStreamsWithError(err error) {
}
}
// TODO: try sending more than one packet
func (s *Session) maybeSendPacket() error {
if !s.sentPacketHandler.AllowsSending() {
return nil