github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/client/serverlist.go (about) 1 package client 2 3 import ( 4 "math/rand" 5 "net" 6 "sort" 7 "strings" 8 "sync" 9 ) 10 11 // serverlist is a prioritized randomized list of nomad servers. Users should 12 // call all() to retrieve the full list, followed by failed(e) on each endpoint 13 // that's failed and good(e) when a valid endpoint is found. 14 type serverlist struct { 15 e endpoints 16 mu sync.RWMutex 17 } 18 19 func newServerList() *serverlist { 20 return &serverlist{} 21 } 22 23 // set the server list to a new list. The new list will be shuffled and sorted 24 // by priority. 25 func (s *serverlist) set(in endpoints) { 26 s.mu.Lock() 27 s.e = in 28 s.mu.Unlock() 29 } 30 31 // all returns a copy of the full server list, shuffled and then sorted by 32 // priority 33 func (s *serverlist) all() endpoints { 34 s.mu.RLock() 35 out := make(endpoints, len(s.e)) 36 copy(out, s.e) 37 s.mu.RUnlock() 38 39 // Randomize the order 40 for i, j := range rand.Perm(len(out)) { 41 out[i], out[j] = out[j], out[i] 42 } 43 44 // Sort by priority 45 sort.Sort(out) 46 return out 47 } 48 49 // failed endpoint will be deprioritized if its still in the list. 50 func (s *serverlist) failed(e *endpoint) { 51 s.mu.Lock() 52 defer s.mu.Unlock() 53 for _, cur := range s.e { 54 if cur.equal(e) { 55 cur.priority++ 56 return 57 } 58 } 59 } 60 61 // good endpoint will get promoted to the highest priority if it's still in the 62 // list. 63 func (s *serverlist) good(e *endpoint) { 64 s.mu.Lock() 65 defer s.mu.Unlock() 66 for _, cur := range s.e { 67 if cur.equal(e) { 68 cur.priority = 0 69 return 70 } 71 } 72 } 73 74 func (e endpoints) Len() int { 75 return len(e) 76 } 77 78 func (e endpoints) Less(i int, j int) bool { 79 // Sort only by priority as endpoints should be shuffled and ordered 80 // only by priority 81 return e[i].priority < e[j].priority 82 } 83 84 func (e endpoints) Swap(i int, j int) { 85 e[i], e[j] = e[j], e[i] 86 } 87 88 type endpoints []*endpoint 89 90 func (e endpoints) String() string { 91 names := make([]string, 0, len(e)) 92 for _, endpoint := range e { 93 names = append(names, endpoint.name) 94 } 95 return strings.Join(names, ",") 96 } 97 98 type endpoint struct { 99 name string 100 addr net.Addr 101 102 // 0 being the highest priority 103 priority int 104 } 105 106 // equal returns true if the name and addr match between two endpoints. 107 // Priority is ignored because the same endpoint may be added by discovery and 108 // heartbeating with different priorities. 109 func (e *endpoint) equal(o *endpoint) bool { 110 return e.name == o.name && e.addr == o.addr 111 }