don't report blocked streams as active for sending data

This commit is contained in:
Marten Seemann
2017-12-22 12:09:11 +07:00
parent c626137608
commit 5371f804f8
11 changed files with 161 additions and 61 deletions

View File

@@ -11,9 +11,8 @@ import (
type baseFlowController struct {
// for sending data
bytesSent protocol.ByteCount
sendWindow protocol.ByteCount
lastBlockedAt protocol.ByteCount
bytesSent protocol.ByteCount
sendWindow protocol.ByteCount
// for receiving data
mutex sync.RWMutex
@@ -78,17 +77,6 @@ func (c *baseFlowController) getWindowUpdate() protocol.ByteCount {
return c.receiveWindow
}
// IsBlocked says if it is newly blocked by flow control.
// For every offset, it only returns true once.
// If it is blocked, the offset is returned.
func (c *baseFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) {
if c.sendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt {
return false, 0
}
c.lastBlockedAt = c.sendWindow
return true, c.sendWindow
}
// maybeAdjustWindowSize increases the receiveWindowSize if we're sending updates too often.
// For details about auto-tuning, see https://docs.google.com/document/d/1SExkMmGiz8VYzV3s9E35JQlJ73vhzCekKkDi85F1qCE/edit?usp=sharing.
func (c *baseFlowController) maybeAdjustWindowSize() {

View File

@@ -49,29 +49,6 @@ var _ = Describe("Base Flow controller", func() {
controller.UpdateSendWindow(10)
Expect(controller.sendWindowSize()).To(Equal(protocol.ByteCount(20)))
})
It("says when it's blocked", func() {
controller.UpdateSendWindow(100)
Expect(controller.IsNewlyBlocked()).To(BeFalse())
controller.AddBytesSent(100)
blocked, offset := controller.IsNewlyBlocked()
Expect(blocked).To(BeTrue())
Expect(offset).To(Equal(protocol.ByteCount(100)))
})
It("doesn't say that it's newly blocked multiple times for the same offset", func() {
controller.UpdateSendWindow(100)
controller.AddBytesSent(100)
newlyBlocked, offset := controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeTrue())
Expect(offset).To(Equal(protocol.ByteCount(100)))
newlyBlocked, _ = controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeFalse())
controller.UpdateSendWindow(150)
controller.AddBytesSent(150)
newlyBlocked, offset = controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeTrue())
})
})
Context("receive flow control", func() {

View File

@@ -10,6 +10,7 @@ import (
)
type connectionFlowController struct {
lastBlockedAt protocol.ByteCount
baseFlowController
}
@@ -36,6 +37,17 @@ func (c *connectionFlowController) SendWindowSize() protocol.ByteCount {
return c.baseFlowController.sendWindowSize()
}
// IsNewlyBlocked says if it is newly blocked by flow control.
// For every offset, it only returns true once.
// If it is blocked, the offset is returned.
func (c *connectionFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) {
if c.sendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt {
return false, 0
}
c.lastBlockedAt = c.sendWindow
return true, c.sendWindow
}
// IncrementHighestReceived adds an increment to the highestReceived value
func (c *connectionFlowController) IncrementHighestReceived(increment protocol.ByteCount) error {
c.mutex.Lock()

View File

@@ -77,6 +77,31 @@ var _ = Describe("Connection Flow controller", func() {
})
})
Context("send flow control", func() {
It("says when it's blocked", func() {
controller.UpdateSendWindow(100)
Expect(controller.IsNewlyBlocked()).To(BeFalse())
controller.AddBytesSent(100)
blocked, offset := controller.IsNewlyBlocked()
Expect(blocked).To(BeTrue())
Expect(offset).To(Equal(protocol.ByteCount(100)))
})
It("doesn't say that it's newly blocked multiple times for the same offset", func() {
controller.UpdateSendWindow(100)
controller.AddBytesSent(100)
newlyBlocked, offset := controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeTrue())
Expect(offset).To(Equal(protocol.ByteCount(100)))
newlyBlocked, _ = controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeFalse())
controller.UpdateSendWindow(150)
controller.AddBytesSent(150)
newlyBlocked, offset = controller.IsNewlyBlocked()
Expect(newlyBlocked).To(BeTrue())
})
})
Context("setting the minimum window size", func() {
var (
oldWindowSize protocol.ByteCount

View File

@@ -5,7 +5,6 @@ import "github.com/lucas-clemente/quic-go/internal/protocol"
type flowController interface {
// for sending
SendWindowSize() protocol.ByteCount
IsNewlyBlocked() (bool, protocol.ByteCount)
UpdateSendWindow(protocol.ByteCount)
AddBytesSent(protocol.ByteCount)
// for receiving
@@ -16,6 +15,8 @@ type flowController interface {
// A StreamFlowController is a flow controller for a QUIC stream.
type StreamFlowController interface {
flowController
// for sending
IsBlocked() (bool, protocol.ByteCount)
// for receiving
// 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
@@ -27,6 +28,8 @@ type StreamFlowController interface {
// The ConnectionFlowController is the flow controller for the connection.
type ConnectionFlowController interface {
flowController
// for sending
IsNewlyBlocked() (bool, protocol.ByteCount)
}
type connectionFlowControllerI interface {

View File

@@ -109,6 +109,15 @@ func (c *streamFlowController) SendWindowSize() protocol.ByteCount {
return window
}
// IsBlocked says if it is blocked by stream-level flow control.
// If it is blocked, the offset is returned.
func (c *streamFlowController) IsBlocked() (bool, protocol.ByteCount) {
if c.sendWindowSize() != 0 {
return false, 0
}
return true, c.sendWindow
}
func (c *streamFlowController) HasWindowUpdate() bool {
c.mutex.Lock()
hasWindowUpdate := !c.receivedFinalOffset && c.hasWindowUpdate()

View File

@@ -247,7 +247,7 @@ var _ = Describe("Stream Flow controller", func() {
controller.AddBytesSent(50)
blocked, _ := controller.connection.IsNewlyBlocked()
Expect(blocked).To(BeTrue())
Expect(controller.IsNewlyBlocked()).To(BeFalse())
Expect(controller.IsBlocked()).To(BeFalse())
})
})
})