github.com/uber/kraken@v0.1.4/tracker/peerhandoutpolicy/peerhandoutpolicy.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package peerhandoutpolicy 15 16 import ( 17 "fmt" 18 "sort" 19 20 "github.com/uber-go/tally" 21 22 "github.com/uber/kraken/core" 23 ) 24 25 type peerPriorityInfo struct { 26 peer *core.PeerInfo 27 priority int 28 label string 29 } 30 31 // assignmentPolicy defines the policy for assigning priority to peers. 32 type assignmentPolicy interface { 33 assignPriority(peer *core.PeerInfo) (priority int, label string) 34 } 35 36 // PriorityPolicy wraps an assignmentPolicy and uses it to sort lists of peers. 37 type PriorityPolicy struct { 38 stats tally.Scope 39 policy assignmentPolicy 40 } 41 42 // NewPriorityPolicy returns a PriorityPolicy that assigns priorities using the given priority policy. 43 func NewPriorityPolicy(stats tally.Scope, priorityPolicy string) (*PriorityPolicy, error) { 44 p := &PriorityPolicy{ 45 stats: stats.Tagged(map[string]string{ 46 "module": "peerhandoutpolicy", 47 "priority": priorityPolicy, 48 }), 49 } 50 51 switch priorityPolicy { 52 case _defaultPolicy: 53 p.policy = newDefaultAssignmentPolicy() 54 case _completenessPolicy: 55 p.policy = newCompletenessAssignmentPolicy() 56 default: 57 return nil, fmt.Errorf("priority policy %q not found", priorityPolicy) 58 } 59 60 return p, nil 61 } 62 63 // SortPeers returns the given list of peers sorted by the priority assigned to them 64 // by the priorityPolicy. Excludes the source peer from the list. 65 func (p *PriorityPolicy) SortPeers(source *core.PeerInfo, peers []*core.PeerInfo) []*core.PeerInfo { 66 67 peerPriorities := make([]*peerPriorityInfo, 0, len(peers)) 68 for k := 0; k < len(peers); k++ { 69 if peers[k] != source { 70 priority, label := p.policy.assignPriority(peers[k]) 71 peerPriorities = append(peerPriorities, 72 &peerPriorityInfo{peers[k], priority, label}) 73 } 74 } 75 76 sort.Slice(peerPriorities, func(i, j int) bool { 77 return peerPriorities[i].priority < peerPriorities[j].priority 78 }) 79 80 priorityCounts := make(map[string]int) 81 for k := 0; k < len(peerPriorities); k++ { 82 p := peerPriorities[k] 83 peers[k] = p.peer 84 if _, ok := priorityCounts[p.label]; ok { 85 priorityCounts[p.label]++ 86 } else { 87 priorityCounts[p.label] = 1 88 } 89 } 90 peers = peers[:len(peerPriorities)] 91 92 for label, count := range priorityCounts { 93 p.stats.Tagged(map[string]string{ 94 "label": label, 95 }).Gauge("count").Update(float64(count)) 96 } 97 98 return peers 99 }