forked from hashicorp/hyparview
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfailure.go
More file actions
117 lines (98 loc) · 2.4 KB
/
Copy pathfailure.go
File metadata and controls
117 lines (98 loc) · 2.4 KB
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
package hyparview
type Send interface {
// Send sends one message at a time to a peer. TODO simplify batching?
// send should use a timeout to detect blocking as failure
Send(Message) (*NeighborRefuse, error)
// Failed is called after hyparview has handled the failure, to handle e.g.
// connection cleanup
Failed(Node)
// Bootstrap sends a join to some server, discovered by some external consideration
Bootstrap() Node
}
// Send wraps the S.Send sender in appropriate error handling
func (v *Hyparview) Send(ms ...Message) {
subs := map[string]Node{}
for i := 0; i < len(ms); {
m := ms[i]
n := m.To()
// Send messages to the replacement node, if we have one
if sub, ok := subs[n.Addr()]; ok {
m = m.AssocTo(sub)
}
_, err := v.S.Send(m)
if err != nil {
v.Active.DelNode(n)
v.S.Failed(n)
sub := v.PromotePassive()
if sub == nil {
// FIXME re-Join
// log.Printf("WARN empty passive view, fail %d", len(ms)-i)
// return
sub = v.S.Bootstrap()
}
subs[n.Addr()] = sub
} else {
// On failure, retry the failed message with the replacement server
i++
}
}
}
func (v *Hyparview) Bootstrap() Node {
return v.S.Bootstrap()
}
func (v *Hyparview) PromotePassive() Node {
return v.PromotePassiveBut(nil)
}
func (v *Hyparview) PromotePassiveBut(peer Node) Node {
pri := v.Active.IsEmpty()
for _, n := range v.Passive.Shuffled() {
if EqualNode(n, peer) {
continue
}
m := NewNeighbor(n, v.Self, pri)
resp, err := v.S.Send(m)
if err != nil {
v.Passive.DelNode(n)
continue
}
if pri == HighPriority {
v.AddActive(n)
v.DelPassive(n)
return n
}
// Low priority, a refuse means we move on but keep the peer
if resp != nil {
continue
}
v.AddActive(n)
v.DelPassive(n)
return n
}
return nil
}
// greedyShuffle tries to populate our active view on RecvShuffle
//
//nolint:unused
func (v *Hyparview) greedyShuffle() {
if !v.Active.IsFull() {
v.PromotePassive()
}
}
// repairAsymmetry handles a message from an unexpected sender
func (v *Hyparview) repairAsymmetry(m Message) {
peer := m.From()
if EqualNode(v.Self, peer) || v.Active.Contains(peer) {
return
}
if v.Active.IsFull() {
v.Send(NewDisconnect(peer, v.Self))
return
}
v.Active.Add(peer)
}
// SendKeepalives actively repairs the active view
func (v *Hyparview) SendKeepalives() {
for _, n := range v.Active.Nodes {
v.Send(NewNeighborKeepalive(n, v.Self))
}
}