-
Notifications
You must be signed in to change notification settings - Fork 227
/
Copy pathleastconnection.go
112 lines (92 loc) · 2.02 KB
/
leastconnection.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
package route
import (
"math/rand"
"time"
)
type LeastConnection struct {
pool *EndpointPool
initialEndpoint string
lastEndpoint *Endpoint
randomize *rand.Rand
}
func NewLeastConnection(p *EndpointPool, initial string) EndpointIterator {
return &LeastConnection{
pool: p,
initialEndpoint: initial,
randomize: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
func (r *LeastConnection) Next() *Endpoint {
var e *endpointElem
if r.initialEndpoint != "" {
e = r.pool.findById(r.initialEndpoint)
r.initialEndpoint = ""
if e != nil && e.isOverloaded() {
e = nil
}
}
if e != nil {
e.RLock()
defer e.RUnlock()
r.lastEndpoint = e.endpoint
return e.endpoint
}
e = r.next()
if e != nil {
e.RLock()
defer e.RUnlock()
r.lastEndpoint = e.endpoint
return e.endpoint
}
r.lastEndpoint = nil
return nil
}
func (r *LeastConnection) PreRequest(e *Endpoint) {
e.Stats.NumberConnections.Increment()
}
func (r *LeastConnection) PostRequest(e *Endpoint) {
e.Stats.NumberConnections.Decrement()
}
func (r *LeastConnection) next() *endpointElem {
r.pool.Lock()
defer r.pool.Unlock()
var selected *endpointElem
// none
total := len(r.pool.endpoints)
if total == 0 {
return nil
}
// single endpoint
if total == 1 {
e := r.pool.endpoints[0]
if e.isOverloaded() {
return nil
}
return e
}
// more than 1 endpoint
// select the least connection endpoint OR
// random one within the least connection endpoints
randIndices := r.randomize.Perm(total)
for i := 0; i < total; i++ {
randIdx := randIndices[i]
cur := r.pool.endpoints[randIdx]
if cur.isOverloaded() {
continue
}
// our first is the least
if i == 0 || selected == nil {
selected = cur
continue
}
if cur.endpoint.Stats.NumberConnections.Count() < selected.endpoint.Stats.NumberConnections.Count() {
selected = cur
}
}
return selected
}
func (r *LeastConnection) EndpointFailed(err error) {
if r.lastEndpoint != nil {
r.pool.EndpointFailed(r.lastEndpoint, err)
}
}