github.com/yimialmonte/fabric@v2.1.1+incompatible/discovery/client/selection.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package discovery 8 9 import ( 10 "math/rand" 11 "sort" 12 "time" 13 14 "github.com/hyperledger/fabric/gossip/protoext" 15 ) 16 17 // Filter filters and sorts the given endorsers 18 type Filter interface { 19 Filter(endorsers Endorsers) Endorsers 20 } 21 22 // ExclusionFilter returns true if the given Peer 23 // is not to be considered when selecting peers 24 type ExclusionFilter interface { 25 // Exclude returns whether the given Peer is to be excluded or not 26 Exclude(Peer) bool 27 } 28 29 type selectionFunc func(Peer) bool 30 31 func (sf selectionFunc) Exclude(p Peer) bool { 32 return sf(p) 33 } 34 35 // PrioritySelector guides the selection of peers via 36 // giving peers a relative priority to their selection 37 type PrioritySelector interface { 38 // Compare compares between 2 peers and returns 39 // their relative scores 40 Compare(Peer, Peer) Priority 41 } 42 43 // Priority defines how likely a peer is to be selected 44 // over another peer. 45 // Positive priority means the left peer is selected 46 // Negative priority means the right peer is selected 47 // Zero priority means their priorities are the same 48 type Priority int 49 50 var ( 51 // PrioritiesByHeight selects peers by descending height 52 PrioritiesByHeight = &byHeight{} 53 // NoExclusion accepts all peers and rejects no peers 54 NoExclusion = selectionFunc(noExclusion) 55 // NoPriorities is indifferent to how it selects peers 56 NoPriorities = &noPriorities{} 57 ) 58 59 type noPriorities struct{} 60 61 func (nc noPriorities) Compare(_ Peer, _ Peer) Priority { 62 return 0 63 } 64 65 type byHeight struct{} 66 67 func (*byHeight) Compare(left Peer, right Peer) Priority { 68 leftHeight := left.StateInfoMessage.GetStateInfo().Properties.LedgerHeight 69 rightHeight := right.StateInfoMessage.GetStateInfo().Properties.LedgerHeight 70 71 if leftHeight > rightHeight { 72 return 1 73 } 74 if rightHeight > leftHeight { 75 return -1 76 } 77 return 0 78 } 79 80 func noExclusion(_ Peer) bool { 81 return false 82 } 83 84 // ExcludeHosts returns a ExclusionFilter that excludes the given endpoints 85 func ExcludeHosts(endpoints ...string) ExclusionFilter { 86 m := make(map[string]struct{}) 87 for _, endpoint := range endpoints { 88 m[endpoint] = struct{}{} 89 } 90 return ExcludeByHost(func(host string) bool { 91 _, excluded := m[host] 92 return excluded 93 }) 94 } 95 96 // ExcludeByHost creates a ExclusionFilter out of the given exclusion predicate 97 func ExcludeByHost(reject func(host string) bool) ExclusionFilter { 98 return selectionFunc(func(p Peer) bool { 99 endpoint := p.AliveMessage.GetAliveMsg().Membership.Endpoint 100 var internalEndpoint string 101 se := p.AliveMessage.GetSecretEnvelope() 102 if se != nil { 103 internalEndpoint = protoext.InternalEndpoint(se) 104 } 105 return reject(endpoint) || reject(internalEndpoint) 106 }) 107 } 108 109 // Filter filters the endorsers according to the given ExclusionFilter 110 func (endorsers Endorsers) Filter(f ExclusionFilter) Endorsers { 111 var res Endorsers 112 for _, e := range endorsers { 113 if !f.Exclude(*e) { 114 res = append(res, e) 115 } 116 } 117 return res 118 } 119 120 // Shuffle sorts the endorsers in random order 121 func (endorsers Endorsers) Shuffle() Endorsers { 122 res := make(Endorsers, len(endorsers)) 123 rand.Seed(time.Now().UnixNano()) 124 for i, index := range rand.Perm(len(endorsers)) { 125 res[i] = endorsers[index] 126 } 127 return res 128 } 129 130 type endorserSort struct { 131 Endorsers 132 PrioritySelector 133 } 134 135 // Sort sorts the endorsers according to the given PrioritySelector 136 func (endorsers Endorsers) Sort(ps PrioritySelector) Endorsers { 137 sort.Sort(&endorserSort{ 138 Endorsers: endorsers, 139 PrioritySelector: ps, 140 }) 141 return endorsers 142 } 143 144 func (es *endorserSort) Len() int { 145 return len(es.Endorsers) 146 } 147 148 func (es *endorserSort) Less(i, j int) bool { 149 e1 := es.Endorsers[i] 150 e2 := es.Endorsers[j] 151 less := es.Compare(*e1, *e2) 152 return less > Priority(0) 153 } 154 155 func (es *endorserSort) Swap(i, j int) { 156 es.Endorsers[i], es.Endorsers[j] = es.Endorsers[j], es.Endorsers[i] 157 }