forked from quic-go/quic-go
queue connection-level window updates from the flow controller directly
It is not sufficient to check for connection-level window updates every time a packet is sent. When a connection-level window update needs to be sent, we need to make sure that it gets sent immediately (i.e. call scheduleSending() in the session).
This commit is contained in:
@@ -12,6 +12,8 @@ import (
|
||||
type connectionFlowController struct {
|
||||
lastBlockedAt protocol.ByteCount
|
||||
baseFlowController
|
||||
|
||||
queueWindowUpdate func()
|
||||
}
|
||||
|
||||
var _ ConnectionFlowController = &connectionFlowController{}
|
||||
@@ -21,6 +23,7 @@ var _ ConnectionFlowController = &connectionFlowController{}
|
||||
func NewConnectionFlowController(
|
||||
receiveWindow protocol.ByteCount,
|
||||
maxReceiveWindow protocol.ByteCount,
|
||||
queueWindowUpdate func(),
|
||||
rttStats *congestion.RTTStats,
|
||||
logger utils.Logger,
|
||||
) ConnectionFlowController {
|
||||
@@ -32,6 +35,7 @@ func NewConnectionFlowController(
|
||||
maxReceiveWindowSize: maxReceiveWindow,
|
||||
logger: logger,
|
||||
},
|
||||
queueWindowUpdate: queueWindowUpdate,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +66,15 @@ func (c *connectionFlowController) IncrementHighestReceived(increment protocol.B
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *connectionFlowController) MaybeQueueWindowUpdate() {
|
||||
c.mutex.Lock()
|
||||
hasWindowUpdate := c.hasWindowUpdate()
|
||||
c.mutex.Unlock()
|
||||
if hasWindowUpdate {
|
||||
c.queueWindowUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connectionFlowController) GetWindowUpdate() protocol.ByteCount {
|
||||
c.mutex.Lock()
|
||||
oldWindowSize := c.receiveWindowSize
|
||||
|
||||
@@ -11,7 +11,10 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("Connection Flow controller", func() {
|
||||
var controller *connectionFlowController
|
||||
var (
|
||||
controller *connectionFlowController
|
||||
queuedWindowUpdate bool
|
||||
)
|
||||
|
||||
// update the congestion such that it returns a given value for the smoothed RTT
|
||||
setRtt := func(t time.Duration) {
|
||||
@@ -23,6 +26,7 @@ var _ = Describe("Connection Flow controller", func() {
|
||||
controller = &connectionFlowController{}
|
||||
controller.rttStats = &congestion.RTTStats{}
|
||||
controller.logger = utils.DefaultLogger
|
||||
controller.queueWindowUpdate = func() { queuedWindowUpdate = true }
|
||||
})
|
||||
|
||||
Context("Constructor", func() {
|
||||
@@ -32,7 +36,7 @@ var _ = Describe("Connection Flow controller", func() {
|
||||
receiveWindow := protocol.ByteCount(2000)
|
||||
maxReceiveWindow := protocol.ByteCount(3000)
|
||||
|
||||
fc := NewConnectionFlowController(receiveWindow, maxReceiveWindow, rttStats, utils.DefaultLogger).(*connectionFlowController)
|
||||
fc := NewConnectionFlowController(receiveWindow, maxReceiveWindow, nil, rttStats, utils.DefaultLogger).(*connectionFlowController)
|
||||
Expect(fc.receiveWindow).To(Equal(receiveWindow))
|
||||
Expect(fc.maxReceiveWindowSize).To(Equal(maxReceiveWindow))
|
||||
})
|
||||
@@ -53,6 +57,18 @@ var _ = Describe("Connection Flow controller", func() {
|
||||
controller.bytesRead = 100 - 60
|
||||
})
|
||||
|
||||
It("queues window updates", func() {
|
||||
controller.MaybeQueueWindowUpdate()
|
||||
Expect(queuedWindowUpdate).To(BeFalse())
|
||||
controller.AddBytesRead(30)
|
||||
controller.MaybeQueueWindowUpdate()
|
||||
Expect(queuedWindowUpdate).To(BeTrue())
|
||||
Expect(controller.GetWindowUpdate()).ToNot(BeZero())
|
||||
queuedWindowUpdate = false
|
||||
controller.MaybeQueueWindowUpdate()
|
||||
Expect(queuedWindowUpdate).To(BeFalse())
|
||||
})
|
||||
|
||||
It("gets a window update", func() {
|
||||
windowSize := controller.receiveWindowSize
|
||||
oldOffset := controller.bytesRead
|
||||
|
||||
@@ -10,6 +10,7 @@ type flowController interface {
|
||||
// for receiving
|
||||
AddBytesRead(protocol.ByteCount)
|
||||
GetWindowUpdate() protocol.ByteCount // returns 0 if no update is necessary
|
||||
MaybeQueueWindowUpdate() // queues a window update, if necessary
|
||||
}
|
||||
|
||||
// A StreamFlowController is a flow controller for a QUIC stream.
|
||||
@@ -21,8 +22,6 @@ type StreamFlowController interface {
|
||||
// UpdateHighestReceived should be called when a new highest offset is received
|
||||
// final has to be to true if this is the final offset of the stream, as contained in a STREAM frame with FIN bit, and the RST_STREAM frame
|
||||
UpdateHighestReceived(offset protocol.ByteCount, final bool) error
|
||||
// MaybeQueueWindowUpdate queues a window update, if necessary
|
||||
MaybeQueueWindowUpdate()
|
||||
}
|
||||
|
||||
// The ConnectionFlowController is the flow controller for the connection.
|
||||
|
||||
@@ -131,6 +131,9 @@ func (c *streamFlowController) MaybeQueueWindowUpdate() {
|
||||
if hasWindowUpdate {
|
||||
c.queueWindowUpdate()
|
||||
}
|
||||
if c.contributesToConnection {
|
||||
c.connection.MaybeQueueWindowUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *streamFlowController) GetWindowUpdate() protocol.ByteCount {
|
||||
|
||||
@@ -13,16 +13,18 @@ import (
|
||||
|
||||
var _ = Describe("Stream Flow controller", func() {
|
||||
var (
|
||||
controller *streamFlowController
|
||||
queuedWindowUpdate bool
|
||||
controller *streamFlowController
|
||||
queuedWindowUpdate bool
|
||||
queuedConnWindowUpdate bool
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
queuedWindowUpdate = false
|
||||
queuedConnWindowUpdate = false
|
||||
rttStats := &congestion.RTTStats{}
|
||||
controller = &streamFlowController{
|
||||
streamID: 10,
|
||||
connection: NewConnectionFlowController(1000, 1000, rttStats, utils.DefaultLogger).(*connectionFlowController),
|
||||
connection: NewConnectionFlowController(1000, 1000, func() { queuedConnWindowUpdate = true }, rttStats, utils.DefaultLogger).(*connectionFlowController),
|
||||
}
|
||||
controller.maxReceiveWindowSize = 10000
|
||||
controller.rttStats = rttStats
|
||||
@@ -37,7 +39,7 @@ var _ = Describe("Stream Flow controller", func() {
|
||||
sendWindow := protocol.ByteCount(4000)
|
||||
|
||||
It("sets the send and receive windows", func() {
|
||||
cc := NewConnectionFlowController(0, 0, nil, utils.DefaultLogger)
|
||||
cc := NewConnectionFlowController(0, 0, nil, nil, utils.DefaultLogger)
|
||||
fc := NewStreamFlowController(5, true, cc, receiveWindow, maxReceiveWindow, sendWindow, nil, rttStats, utils.DefaultLogger).(*streamFlowController)
|
||||
Expect(fc.streamID).To(Equal(protocol.StreamID(5)))
|
||||
Expect(fc.receiveWindow).To(Equal(receiveWindow))
|
||||
@@ -53,7 +55,7 @@ var _ = Describe("Stream Flow controller", func() {
|
||||
queued = true
|
||||
}
|
||||
|
||||
cc := NewConnectionFlowController(0, 0, nil, utils.DefaultLogger)
|
||||
cc := NewConnectionFlowController(0, 0, nil, nil, utils.DefaultLogger)
|
||||
fc := NewStreamFlowController(5, true, cc, receiveWindow, maxReceiveWindow, sendWindow, queueWindowUpdate, rttStats, utils.DefaultLogger).(*streamFlowController)
|
||||
fc.AddBytesRead(receiveWindow)
|
||||
fc.MaybeQueueWindowUpdate()
|
||||
@@ -189,6 +191,7 @@ var _ = Describe("Stream Flow controller", func() {
|
||||
controller.receiveWindow = 100
|
||||
controller.receiveWindowSize = 60
|
||||
controller.bytesRead = 100 - 60
|
||||
controller.connection.(*connectionFlowController).receiveWindow = 100
|
||||
controller.connection.(*connectionFlowController).receiveWindowSize = 120
|
||||
oldWindowSize = controller.receiveWindowSize
|
||||
})
|
||||
@@ -205,6 +208,15 @@ var _ = Describe("Stream Flow controller", func() {
|
||||
Expect(queuedWindowUpdate).To(BeFalse())
|
||||
})
|
||||
|
||||
It("queues connection-level window updates", func() {
|
||||
controller.contributesToConnection = true
|
||||
controller.MaybeQueueWindowUpdate()
|
||||
Expect(queuedConnWindowUpdate).To(BeFalse())
|
||||
controller.AddBytesRead(60)
|
||||
controller.MaybeQueueWindowUpdate()
|
||||
Expect(queuedConnWindowUpdate).To(BeTrue())
|
||||
})
|
||||
|
||||
It("tells the connection flow controller when the window was autotuned", func() {
|
||||
oldOffset := controller.bytesRead
|
||||
controller.contributesToConnection = true
|
||||
|
||||
Reference in New Issue
Block a user