mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-02 19:57:35 +03:00
185 lines
6.1 KiB
Go
185 lines
6.1 KiB
Go
package flowcontrol
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Connection Flow controller", func() {
|
|
var (
|
|
controller *connectionFlowController
|
|
queuedWindowUpdate bool
|
|
)
|
|
|
|
// update the congestion such that it returns a given value for the smoothed RTT
|
|
setRtt := func(t time.Duration) {
|
|
controller.rttStats.UpdateRTT(t, 0, time.Now())
|
|
Expect(controller.rttStats.SmoothedRTT()).To(Equal(t)) // make sure it worked
|
|
}
|
|
|
|
BeforeEach(func() {
|
|
queuedWindowUpdate = false
|
|
controller = &connectionFlowController{}
|
|
controller.rttStats = &utils.RTTStats{}
|
|
controller.logger = utils.DefaultLogger
|
|
controller.queueWindowUpdate = func() { queuedWindowUpdate = true }
|
|
controller.allowWindowIncrease = func(protocol.ByteCount) bool { return true }
|
|
})
|
|
|
|
Context("Constructor", func() {
|
|
rttStats := &utils.RTTStats{}
|
|
|
|
It("sets the send and receive windows", func() {
|
|
receiveWindow := protocol.ByteCount(2000)
|
|
maxReceiveWindow := protocol.ByteCount(3000)
|
|
|
|
fc := NewConnectionFlowController(
|
|
receiveWindow,
|
|
maxReceiveWindow,
|
|
nil,
|
|
func(protocol.ByteCount) bool { return true },
|
|
rttStats,
|
|
utils.DefaultLogger).(*connectionFlowController)
|
|
Expect(fc.receiveWindow).To(Equal(receiveWindow))
|
|
Expect(fc.maxReceiveWindowSize).To(Equal(maxReceiveWindow))
|
|
})
|
|
})
|
|
|
|
Context("receive flow control", func() {
|
|
It("increases the highestReceived by a given window size", func() {
|
|
controller.highestReceived = 1337
|
|
controller.IncrementHighestReceived(123)
|
|
Expect(controller.highestReceived).To(Equal(protocol.ByteCount(1337 + 123)))
|
|
})
|
|
|
|
Context("getting window updates", func() {
|
|
BeforeEach(func() {
|
|
controller.receiveWindow = 100
|
|
controller.receiveWindowSize = 60
|
|
controller.maxReceiveWindowSize = 1000
|
|
controller.bytesRead = 100 - 60
|
|
})
|
|
|
|
It("queues window updates", func() {
|
|
controller.AddBytesRead(1)
|
|
Expect(queuedWindowUpdate).To(BeFalse())
|
|
controller.AddBytesRead(29)
|
|
Expect(queuedWindowUpdate).To(BeTrue())
|
|
Expect(controller.GetWindowUpdate()).ToNot(BeZero())
|
|
queuedWindowUpdate = false
|
|
controller.AddBytesRead(1)
|
|
Expect(queuedWindowUpdate).To(BeFalse())
|
|
})
|
|
|
|
It("gets a window update", func() {
|
|
windowSize := controller.receiveWindowSize
|
|
oldOffset := controller.bytesRead
|
|
dataRead := windowSize/2 - 1 // make sure not to trigger auto-tuning
|
|
controller.AddBytesRead(dataRead)
|
|
offset := controller.GetWindowUpdate()
|
|
Expect(offset).To(Equal(oldOffset + dataRead + 60))
|
|
})
|
|
|
|
It("auto-tunes the window", func() {
|
|
var allowed protocol.ByteCount
|
|
controller.allowWindowIncrease = func(size protocol.ByteCount) bool {
|
|
allowed = size
|
|
return true
|
|
}
|
|
oldOffset := controller.bytesRead
|
|
oldWindowSize := controller.receiveWindowSize
|
|
rtt := scaleDuration(20 * time.Millisecond)
|
|
setRtt(rtt)
|
|
controller.epochStartTime = time.Now().Add(-time.Millisecond)
|
|
controller.epochStartOffset = oldOffset
|
|
dataRead := oldWindowSize/2 + 1
|
|
controller.AddBytesRead(dataRead)
|
|
offset := controller.GetWindowUpdate()
|
|
newWindowSize := controller.receiveWindowSize
|
|
Expect(newWindowSize).To(Equal(2 * oldWindowSize))
|
|
Expect(offset).To(Equal(oldOffset + dataRead + newWindowSize))
|
|
Expect(allowed).To(Equal(oldWindowSize))
|
|
})
|
|
|
|
It("doesn't auto-tune the window if it's not allowed", func() {
|
|
controller.allowWindowIncrease = func(protocol.ByteCount) bool { return false }
|
|
oldOffset := controller.bytesRead
|
|
oldWindowSize := controller.receiveWindowSize
|
|
rtt := scaleDuration(20 * time.Millisecond)
|
|
setRtt(rtt)
|
|
controller.epochStartTime = time.Now().Add(-time.Millisecond)
|
|
controller.epochStartOffset = oldOffset
|
|
dataRead := oldWindowSize/2 + 1
|
|
controller.AddBytesRead(dataRead)
|
|
offset := controller.GetWindowUpdate()
|
|
newWindowSize := controller.receiveWindowSize
|
|
Expect(newWindowSize).To(Equal(oldWindowSize))
|
|
Expect(offset).To(Equal(oldOffset + dataRead + newWindowSize))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("setting the minimum window size", func() {
|
|
var (
|
|
oldWindowSize protocol.ByteCount
|
|
receiveWindow protocol.ByteCount = 10000
|
|
receiveWindowSize protocol.ByteCount = 1000
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
controller.receiveWindow = receiveWindow
|
|
controller.receiveWindowSize = receiveWindowSize
|
|
oldWindowSize = controller.receiveWindowSize
|
|
controller.maxReceiveWindowSize = 3000
|
|
})
|
|
|
|
It("sets the minimum window window size", func() {
|
|
controller.EnsureMinimumWindowSize(1800)
|
|
Expect(controller.receiveWindowSize).To(Equal(protocol.ByteCount(1800)))
|
|
})
|
|
|
|
It("doesn't reduce the window window size", func() {
|
|
controller.EnsureMinimumWindowSize(1)
|
|
Expect(controller.receiveWindowSize).To(Equal(oldWindowSize))
|
|
})
|
|
|
|
It("doesn't increase the window size beyond the maxReceiveWindowSize", func() {
|
|
max := controller.maxReceiveWindowSize
|
|
controller.EnsureMinimumWindowSize(2 * max)
|
|
Expect(controller.receiveWindowSize).To(Equal(max))
|
|
})
|
|
|
|
It("starts a new epoch after the window size was increased", func() {
|
|
controller.EnsureMinimumWindowSize(1912)
|
|
Expect(controller.epochStartTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond))
|
|
})
|
|
})
|
|
|
|
Context("resetting", func() {
|
|
It("resets", func() {
|
|
const initialWindow protocol.ByteCount = 1337
|
|
controller.UpdateSendWindow(initialWindow)
|
|
controller.AddBytesSent(1000)
|
|
Expect(controller.SendWindowSize()).To(Equal(initialWindow - 1000))
|
|
Expect(controller.Reset()).To(Succeed())
|
|
Expect(controller.SendWindowSize()).To(Equal(initialWindow))
|
|
})
|
|
|
|
It("says if is blocked after resetting", func() {
|
|
const initialWindow protocol.ByteCount = 1337
|
|
controller.UpdateSendWindow(initialWindow)
|
|
controller.AddBytesSent(initialWindow)
|
|
blocked, _ := controller.IsNewlyBlocked()
|
|
Expect(blocked).To(BeTrue())
|
|
Expect(controller.Reset()).To(Succeed())
|
|
controller.AddBytesSent(initialWindow)
|
|
blocked, blockedAt := controller.IsNewlyBlocked()
|
|
Expect(blocked).To(BeTrue())
|
|
Expect(blockedAt).To(Equal(initialWindow))
|
|
})
|
|
})
|
|
})
|