parent
0d7a57fa9d
commit
62266010ac
11 changed files with 63 additions and 20 deletions
|
@ -136,21 +136,21 @@ func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory {
|
||||||
// LastDelay return last history record. if proxy is not alive, return the max value of uint16.
|
// LastDelay return last history record. if proxy is not alive, return the max value of uint16.
|
||||||
// implements C.Proxy
|
// implements C.Proxy
|
||||||
func (p *Proxy) LastDelay() (delay uint16) {
|
func (p *Proxy) LastDelay() (delay uint16) {
|
||||||
var maxDelay uint16 = 0xffff
|
var max uint16 = 0xffff
|
||||||
if !p.alive.Load() {
|
if !p.alive.Load() {
|
||||||
return maxDelay
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
history := p.history.Last()
|
history := p.history.Last()
|
||||||
if history.Delay == 0 {
|
if history.Delay == 0 {
|
||||||
return maxDelay
|
return max
|
||||||
}
|
}
|
||||||
return history.Delay
|
return history.Delay
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastDelayForTestUrl implements C.Proxy
|
// LastDelayForTestUrl implements C.Proxy
|
||||||
func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) {
|
func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) {
|
||||||
var maxDelay uint16 = 0xffff
|
var max uint16 = 0xffff
|
||||||
|
|
||||||
alive := p.alive.Load()
|
alive := p.alive.Load()
|
||||||
history := p.history.Last()
|
history := p.history.Last()
|
||||||
|
@ -161,11 +161,11 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alive {
|
if !alive {
|
||||||
return maxDelay
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
if history.Delay == 0 {
|
if history.Delay == 0 {
|
||||||
return maxDelay
|
return max
|
||||||
}
|
}
|
||||||
return history.Delay
|
return history.Delay
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,16 +85,16 @@ func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) {
|
||||||
func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
|
func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
|
||||||
iter := iterator[int]([]int{1, 2, 3, 4, 5})
|
iter := iterator[int]([]int{1, 2, 3, 4, 5})
|
||||||
src := NewObservable[int](iter)
|
src := NewObservable[int](iter)
|
||||||
total := 100
|
max := 100
|
||||||
|
|
||||||
var list []Subscription[int]
|
var list []Subscription[int]
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < max; i++ {
|
||||||
ch, _ := src.Subscribe()
|
ch, _ := src.Subscribe()
|
||||||
list = append(list, ch)
|
list = append(list, ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(total)
|
wg.Add(max)
|
||||||
waitCh := func(ch <-chan int) {
|
waitCh := func(ch <-chan int) {
|
||||||
for range ch {
|
for range ch {
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module github.com/Dreamacro/clash
|
module github.com/Dreamacro/clash
|
||||||
|
|
||||||
go 1.21
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/3andne/restls-client-go v0.1.6
|
github.com/3andne/restls-client-go v0.1.6
|
||||||
|
|
|
@ -3,6 +3,8 @@ package updater
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LimitReachedError records the limit and the operation that caused it.
|
// LimitReachedError records the limit and the operation that caused it.
|
||||||
|
@ -33,7 +35,7 @@ func (lr *limitedReader) Read(p []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = p[:min(lr.n, int64(len(p)))]
|
p = p[:Min(lr.n, int64(len(p)))]
|
||||||
|
|
||||||
n, err = lr.r.Read(p)
|
n, err = lr.r.Read(p)
|
||||||
lr.n -= int64(n)
|
lr.n -= int64(n)
|
||||||
|
@ -54,3 +56,12 @@ func LimitReader(r io.Reader, n int64) (limited io.Reader, err error) {
|
||||||
n: n,
|
n: n,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Min returns the smaller of x or y.
|
||||||
|
func Min[T constraints.Integer | ~string](x, y T) (res T) {
|
||||||
|
if x < y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
|
@ -186,7 +186,7 @@ func (c *Cubic) CongestionWindowAfterAck(
|
||||||
targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow
|
targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow
|
||||||
}
|
}
|
||||||
// Limit the CWND increase to half the acked bytes.
|
// Limit the CWND increase to half the acked bytes.
|
||||||
targetCongestionWindow = min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2)
|
targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2)
|
||||||
|
|
||||||
// Increase the window by approximately Alpha * 1 MSS of bytes every
|
// Increase the window by approximately Alpha * 1 MSS of bytes every
|
||||||
// time we ack an estimated tcp window of bytes. For small
|
// time we ack an estimated tcp window of bytes. For small
|
||||||
|
|
|
@ -177,7 +177,7 @@ func (c *cubicSender) OnPacketAcked(
|
||||||
priorInFlight congestion.ByteCount,
|
priorInFlight congestion.ByteCount,
|
||||||
eventTime time.Time,
|
eventTime time.Time,
|
||||||
) {
|
) {
|
||||||
c.largestAckedPacketNumber = max(ackedPacketNumber, c.largestAckedPacketNumber)
|
c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber)
|
||||||
if c.InRecovery() {
|
if c.InRecovery() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ func (c *cubicSender) maybeIncreaseCwnd(
|
||||||
c.numAckedPackets = 0
|
c.numAckedPackets = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.congestionWindow = min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime))
|
c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,8 +74,8 @@ func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT ti
|
||||||
// Divide minRTT by 8 to get a rtt increase threshold for exiting.
|
// Divide minRTT by 8 to get a rtt increase threshold for exiting.
|
||||||
minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp)
|
minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp)
|
||||||
// Ensure the rtt threshold is never less than 2ms or more than 16ms.
|
// Ensure the rtt threshold is never less than 2ms or more than 16ms.
|
||||||
minRTTincreaseThresholdUs = min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs)
|
minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs)
|
||||||
minRTTincreaseThreshold := time.Duration(max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond
|
minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond
|
||||||
|
|
||||||
if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) {
|
if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) {
|
||||||
s.hystartFound = true
|
s.hystartFound = true
|
||||||
|
|
|
@ -16,7 +16,7 @@ func MinNonZeroDuration(a, b time.Duration) time.Duration {
|
||||||
if b == 0 {
|
if b == 0 {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return min(a, b)
|
return Min(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbsDuration returns the absolute value of a time duration
|
// AbsDuration returns the absolute value of a time duration
|
||||||
|
|
19
transport/tuic/congestion/minmax_go120.go
Normal file
19
transport/tuic/congestion/minmax_go120.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//go:build !go1.21
|
||||||
|
|
||||||
|
package congestion
|
||||||
|
|
||||||
|
import "golang.org/x/exp/constraints"
|
||||||
|
|
||||||
|
func Max[T constraints.Ordered](a, b T) T {
|
||||||
|
if a < b {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func Min[T constraints.Ordered](a, b T) T {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
13
transport/tuic/congestion/minmax_go121.go
Normal file
13
transport/tuic/congestion/minmax_go121.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//go:build go1.21
|
||||||
|
|
||||||
|
package congestion
|
||||||
|
|
||||||
|
import "cmp"
|
||||||
|
|
||||||
|
func Max[T cmp.Ordered](a, b T) T {
|
||||||
|
return max(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Min[T cmp.Ordered](a, b T) T {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
|
@ -52,11 +52,11 @@ func (p *pacer) Budget(now time.Time) congestion.ByteCount {
|
||||||
return p.maxBurstSize()
|
return p.maxBurstSize()
|
||||||
}
|
}
|
||||||
budget := p.budgetAtLastSent + (congestion.ByteCount(p.getAdjustedBandwidth())*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9
|
budget := p.budgetAtLastSent + (congestion.ByteCount(p.getAdjustedBandwidth())*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9
|
||||||
return min(p.maxBurstSize(), budget)
|
return Min(p.maxBurstSize(), budget)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pacer) maxBurstSize() congestion.ByteCount {
|
func (p *pacer) maxBurstSize() congestion.ByteCount {
|
||||||
return max(
|
return Max(
|
||||||
congestion.ByteCount(uint64((MinPacingDelay+TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9,
|
congestion.ByteCount(uint64((MinPacingDelay+TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9,
|
||||||
maxBurstSizePackets*p.maxDatagramSize,
|
maxBurstSizePackets*p.maxDatagramSize,
|
||||||
)
|
)
|
||||||
|
@ -68,7 +68,7 @@ func (p *pacer) TimeUntilSend() time.Time {
|
||||||
if p.budgetAtLastSent >= p.maxDatagramSize {
|
if p.budgetAtLastSent >= p.maxDatagramSize {
|
||||||
return time.Time{}
|
return time.Time{}
|
||||||
}
|
}
|
||||||
return p.lastSentTime.Add(max(
|
return p.lastSentTime.Add(Max(
|
||||||
MinPacingDelay,
|
MinPacingDelay,
|
||||||
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond,
|
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond,
|
||||||
))
|
))
|
||||||
|
|
Loading…
Reference in a new issue