-
Notifications
You must be signed in to change notification settings - Fork 0
/
selection.go
157 lines (131 loc) · 3.76 KB
/
selection.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package discovery
import (
"math/rand"
"sort"
"time"
"github.com/hyperledger/fabric/gossip/protoext"
)
// Filter filters and sorts the given endorsers
type Filter interface {
Filter(endorsers Endorsers) Endorsers
}
// ExclusionFilter returns true if the given Peer
// is not to be considered when selecting peers
type ExclusionFilter interface {
// Exclude returns whether the given Peer is to be excluded or not
Exclude(Peer) bool
}
type selectionFunc func(Peer) bool
func (sf selectionFunc) Exclude(p Peer) bool {
return sf(p)
}
// PrioritySelector guides the selection of peers via
// giving peers a relative priority to their selection
type PrioritySelector interface {
// Compare compares between 2 peers and returns
// their relative scores
Compare(Peer, Peer) Priority
}
// Priority defines how likely a peer is to be selected
// over another peer.
// Positive priority means the left peer is selected
// Negative priority means the right peer is selected
// Zero priority means their priorities are the same
type Priority int
var (
// PrioritiesByHeight selects peers by descending height
PrioritiesByHeight = &byHeight{}
// NoExclusion accepts all peers and rejects no peers
NoExclusion = selectionFunc(noExclusion)
// NoPriorities is indifferent to how it selects peers
NoPriorities = &noPriorities{}
)
type noPriorities struct{}
func (nc noPriorities) Compare(_ Peer, _ Peer) Priority {
return 0
}
type byHeight struct{}
func (*byHeight) Compare(left Peer, right Peer) Priority {
leftHeight := left.StateInfoMessage.GetStateInfo().Properties.LedgerHeight
rightHeight := right.StateInfoMessage.GetStateInfo().Properties.LedgerHeight
if leftHeight > rightHeight {
return 1
}
if rightHeight > leftHeight {
return -1
}
return 0
}
func noExclusion(_ Peer) bool {
return false
}
// ExcludeHosts returns a ExclusionFilter that excludes the given endpoints
func ExcludeHosts(endpoints ...string) ExclusionFilter {
m := make(map[string]struct{})
for _, endpoint := range endpoints {
m[endpoint] = struct{}{}
}
return ExcludeByHost(func(host string) bool {
_, excluded := m[host]
return excluded
})
}
// ExcludeByHost creates a ExclusionFilter out of the given exclusion predicate
func ExcludeByHost(reject func(host string) bool) ExclusionFilter {
return selectionFunc(func(p Peer) bool {
endpoint := p.AliveMessage.GetAliveMsg().Membership.Endpoint
var internalEndpoint string
se := p.AliveMessage.GetSecretEnvelope()
if se != nil {
internalEndpoint = protoext.InternalEndpoint(se)
}
return reject(endpoint) || reject(internalEndpoint)
})
}
// Filter filters the endorsers according to the given ExclusionFilter
func (endorsers Endorsers) Filter(f ExclusionFilter) Endorsers {
var res Endorsers
for _, e := range endorsers {
if !f.Exclude(*e) {
res = append(res, e)
}
}
return res
}
// Shuffle sorts the endorsers in random order
func (endorsers Endorsers) Shuffle() Endorsers {
res := make(Endorsers, len(endorsers))
rand.Seed(time.Now().UnixNano())
for i, index := range rand.Perm(len(endorsers)) {
res[i] = endorsers[index]
}
return res
}
type endorserSort struct {
Endorsers
PrioritySelector
}
// Sort sorts the endorsers according to the given PrioritySelector
func (endorsers Endorsers) Sort(ps PrioritySelector) Endorsers {
sort.Sort(&endorserSort{
Endorsers: endorsers,
PrioritySelector: ps,
})
return endorsers
}
func (es *endorserSort) Len() int {
return len(es.Endorsers)
}
func (es *endorserSort) Less(i, j int) bool {
e1 := es.Endorsers[i]
e2 := es.Endorsers[j]
less := es.Compare(*e1, *e2)
return less > Priority(0)
}
func (es *endorserSort) Swap(i, j int) {
es.Endorsers[i], es.Endorsers[j] = es.Endorsers[j], es.Endorsers[i]
}