-
Notifications
You must be signed in to change notification settings - Fork 1
/
node.go
112 lines (93 loc) · 2.15 KB
/
node.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 graylog
import (
"bytes"
"fmt"
"math/rand"
"sync/atomic"
"github.com/Graylog2/go-gelf/gelf"
)
var randIntn = rand.Intn
// NOTE: do not change the value of node status
// if you do want the modification happen
// please also update default status in NewNode to Alive
const (
nodeStatusAlive = 0
nodeStatusDead = 1
)
type node struct {
// health check
healthCheckURL string
status *uint32
// log write
udpAddress string
logWriter *gelf.Writer
// weight of node used for node selection
weight int
}
func newNode(config NodeConfig) (*node, error) {
writer, err := gelf.NewWriter(config.UDPAddress)
if err != nil {
return nil, err
}
return &node{
healthCheckURL: config.HealthCheckURL,
status: new(uint32), // default status to Alive
udpAddress: config.UDPAddress,
weight: config.Weight,
logWriter: writer,
}, nil
}
func (n node) alive() bool {
return atomic.LoadUint32(n.status) == nodeStatusAlive
}
func (n *node) setStatus(status uint32) {
switch status {
case nodeStatusAlive, nodeStatusDead:
atomic.StoreUint32(n.status, status)
default:
errorLogger.Panicf("unknown node status %v", status)
}
}
func (n node) getWeight() int {
if !n.alive() {
return 0
}
return n.weight
}
func (n *node) String() string {
return fmt.Sprintf("udp_address=%v weight=%v alive=%v health_check_url=%v\n", n.udpAddress, n.weight, n.alive(), n.healthCheckURL)
}
type nodes []*node
// selectNode using weighted-random algorithm
// http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/
func (ns nodes) selectNode() *node {
total := ns.totalWeight()
if total <= 0 {
errorLogger.Printf("total weight of nodes is %v\n", total)
return nil
}
var selectedNode *node
seed := randIntn(total)
for _, node := range ns {
seed -= node.getWeight()
if seed < 0 {
selectedNode = node
break
}
}
return selectedNode
}
func (ns nodes) totalWeight() int {
sum := 0
for _, node := range ns {
sum += node.getWeight()
}
return sum
}
func (ns nodes) String() string {
buf := bytes.NewBuffer(nil)
for _, node := range ns {
buf.WriteString(node.String())
}
return buf.String()
}