-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathfetch-algo.go
119 lines (101 loc) · 2.19 KB
/
fetch-algo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package segmented
import (
"math"
"time"
"github.com/zyedidia/generic/list"
)
const (
cubicIw = 2
cubicC = 0.4
cubicBeta = 0.7
cubicAlpha = 3 * (1 - cubicBeta) / (1 + cubicBeta)
)
type cubic struct {
t0 int64
cwnd float64
wMax float64
wLastMax float64
k float64
ssthresh float64
}
func (ca *cubic) Cwnd() int {
return max(cubicIw, int(ca.cwnd))
}
func (ca *cubic) Increase(now time.Time, rtt time.Duration) {
nowV := now.UnixNano()
if nowV <= ca.t0 {
return
}
if ca.cwnd < ca.ssthresh { // slow start
ca.cwnd += 1.0
return
}
t := float64(nowV-ca.t0) / float64(time.Second)
rttV := rtt.Seconds()
wCubic := cubicC*math.Pow(t-ca.k, 3) + ca.wMax
wEst := ca.wMax*cubicBeta + cubicAlpha*(t/rttV)
if wCubic < wEst { // TCP friendly region
ca.cwnd = wEst
return
}
// concave region or convex region
// note: RFC8312 specifies `(W_cubic(t+RTT) - cwnd) / cwnd`, but NDN-DPDK benchmark shows
// that using `(W_cubic(t) - cwnd) / cwnd` increases throughput by 10%
ca.cwnd += (wCubic - ca.cwnd) / ca.cwnd
}
func (ca *cubic) Decrease(now time.Time) {
ca.t0 = now.UnixNano()
if ca.cwnd < ca.wLastMax {
ca.wLastMax = ca.cwnd
ca.wMax = ca.cwnd * (1 + cubicBeta) / 2
} else {
ca.wMax = ca.cwnd
ca.wLastMax = ca.cwnd
}
ca.k = math.Cbrt(ca.wMax * (1 - cubicBeta) / cubicC)
ca.cwnd *= cubicBeta
ca.ssthresh = max(ca.cwnd, 2)
}
func newCubic() (ca *cubic) {
return &cubic{
cwnd: cubicIw,
ssthresh: math.Inf(1),
}
}
type fetchSeg struct {
TxTime time.Time
RtoExpiry time.Time
NRetx int
RetxQNode *list.Node[uint64]
}
func (fs *fetchSeg) setTimeNow(rto time.Duration) {
fs.TxTime = time.Now()
fs.RtoExpiry = fs.TxTime.Add(rto)
}
type retxQueue struct {
L *list.List[uint64]
N int
}
func (q *retxQueue) Push(seg uint64, fs *fetchSeg) {
q.L.PushBack(seg)
fs.RetxQNode = q.L.Back
q.N++
}
func (q *retxQueue) Pop(m map[uint64]*fetchSeg) (seg uint64, fs *fetchSeg) {
seg = q.L.Front.Value
fs = m[seg]
q.Delete(fs)
return
}
func (q *retxQueue) Delete(fs *fetchSeg) {
if fs.RetxQNode == nil {
return
}
q.L.Remove(fs.RetxQNode)
fs.RetxQNode = nil
q.N--
}
func makeRetxQueue() (q retxQueue) {
q.L = list.New[uint64]()
return
}