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  }