forked from smallnest/weighted
-
Notifications
You must be signed in to change notification settings - Fork 0
/
roundrobin_weighted.go
106 lines (95 loc) · 1.71 KB
/
roundrobin_weighted.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
package weighted
// rrWeighted is a wrapped weighted item that is used to implement LVS weighted round robin algorithm.
type rrWeighted struct {
Item interface{}
Weight int
}
// RRW is a struct that contains weighted items implement LVS weighted round robin algorithm.
//
// http://kb.linuxvirtualitem.org/wiki/Weighted_Round-Robin_Scheduling
// http://zh.linuxvirtualitem.org/node/37
type RRW struct {
items []*rrWeighted
n int
gcd int
maxW int
i int
cw int
}
// Add a weighted item.
func (w *RRW) Add(item interface{}, weight int) {
weighted := &rrWeighted{Item: item, Weight: weight}
if weight > 0 {
if w.gcd == 0 {
w.gcd = weight
w.maxW = weight
w.i = -1
w.cw = 0
} else {
w.gcd = gcd(w.gcd, weight)
if w.maxW < weight {
w.maxW = weight
}
}
}
w.items = append(w.items, weighted)
w.n++
}
// All returns all items.
func (w *RRW) All() map[interface{}]int {
m := make(map[interface{}]int)
for _, i := range w.items {
m[i.Item] = i.Weight
}
return m
}
// RemoveAll removes all weighted items.
func (w *RRW) RemoveAll() {
w.items = w.items[:0]
w.n = 0
w.gcd = 0
w.maxW = 0
w.i = -1
w.cw = 0
}
// Reset resets all current weights.
func (w *RRW) Reset() {
w.i = -1
w.cw = 0
}
// Next returns next selected item.
func (w *RRW) Next() interface{} {
if w.n == 0 {
return nil
}
if w.n == 1 {
return w.items[0].Item
}
for {
w.i = (w.i + 1) % w.n
if w.i == 0 {
w.cw = w.cw - w.gcd
if w.cw <= 0 {
w.cw = w.maxW
if w.cw == 0 {
return nil
}
}
}
if w.items[w.i].Weight >= w.cw {
return w.items[w.i].Item
}
}
}
func gcd(x, y int) int {
var t int
for {
t = (x % y)
if t > 0 {
x = y
y = t
} else {
return y
}
}
}