route/vendor/github.com/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go

109 lines
3.3 KiB
Go
Raw Normal View History

2018-01-03 19:19:49 +00:00
package flowcontrol
import (
"sync"
"time"
"github.com/lucas-clemente/quic-go/congestion"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
type baseFlowController struct {
2018-01-20 18:07:01 +00:00
// for sending data
2018-01-03 19:19:49 +00:00
bytesSent protocol.ByteCount
sendWindow protocol.ByteCount
2018-01-20 18:07:01 +00:00
// for receiving data
mutex sync.RWMutex
bytesRead protocol.ByteCount
highestReceived protocol.ByteCount
receiveWindow protocol.ByteCount
receiveWindowSize protocol.ByteCount
maxReceiveWindowSize protocol.ByteCount
epochStartTime time.Time
epochStartOffset protocol.ByteCount
rttStats *congestion.RTTStats
2018-01-03 19:19:49 +00:00
}
func (c *baseFlowController) AddBytesSent(n protocol.ByteCount) {
c.bytesSent += n
}
// UpdateSendWindow should be called after receiving a WindowUpdateFrame
// it returns true if the window was actually updated
func (c *baseFlowController) UpdateSendWindow(offset protocol.ByteCount) {
if offset > c.sendWindow {
c.sendWindow = offset
}
}
func (c *baseFlowController) sendWindowSize() protocol.ByteCount {
// this only happens during connection establishment, when data is sent before we receive the peer's transport parameters
if c.bytesSent > c.sendWindow {
return 0
}
return c.sendWindow - c.bytesSent
}
func (c *baseFlowController) AddBytesRead(n protocol.ByteCount) {
c.mutex.Lock()
defer c.mutex.Unlock()
// pretend we sent a WindowUpdate when reading the first byte
2018-01-20 18:07:01 +00:00
// this way auto-tuning of the window size already works for the first WindowUpdate
2018-01-03 19:19:49 +00:00
if c.bytesRead == 0 {
2018-01-20 18:07:01 +00:00
c.startNewAutoTuningEpoch()
2018-01-03 19:19:49 +00:00
}
c.bytesRead += n
}
2018-01-20 18:07:01 +00:00
func (c *baseFlowController) hasWindowUpdate() bool {
bytesRemaining := c.receiveWindow - c.bytesRead
// update the window when more than the threshold was consumed
return bytesRemaining <= protocol.ByteCount((float64(c.receiveWindowSize) * float64((1 - protocol.WindowUpdateThreshold))))
}
2018-01-03 19:19:49 +00:00
// getWindowUpdate updates the receive window, if necessary
// it returns the new offset
func (c *baseFlowController) getWindowUpdate() protocol.ByteCount {
2018-01-20 18:07:01 +00:00
if !c.hasWindowUpdate() {
2018-01-03 19:19:49 +00:00
return 0
}
2018-01-20 18:07:01 +00:00
c.maybeAdjustWindowSize()
c.receiveWindow = c.bytesRead + c.receiveWindowSize
2018-01-03 19:19:49 +00:00
return c.receiveWindow
}
2018-01-20 18:07:01 +00:00
// 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() {
bytesReadInEpoch := c.bytesRead - c.epochStartOffset
// don't do anything if less than half the window has been consumed
if bytesReadInEpoch <= c.receiveWindowSize/2 {
2018-01-03 19:19:49 +00:00
return
}
rtt := c.rttStats.SmoothedRTT()
if rtt == 0 {
return
}
2018-01-20 18:07:01 +00:00
fraction := float64(bytesReadInEpoch) / float64(c.receiveWindowSize)
if time.Since(c.epochStartTime) < time.Duration(4*fraction*float64(rtt)) {
// window is consumed too fast, try to increase the window size
c.receiveWindowSize = utils.MinByteCount(2*c.receiveWindowSize, c.maxReceiveWindowSize)
2018-01-03 19:19:49 +00:00
}
2018-01-20 18:07:01 +00:00
c.startNewAutoTuningEpoch()
}
func (c *baseFlowController) startNewAutoTuningEpoch() {
c.epochStartTime = time.Now()
c.epochStartOffset = c.bytesRead
2018-01-03 19:19:49 +00:00
}
func (c *baseFlowController) checkFlowControlViolation() bool {
return c.highestReceived > c.receiveWindow
}