package protocol import ( "sync" ) type ServerList struct { sync.RWMutex servers []*ServerSpec } func NewServerList() *ServerList { return &ServerList{} } func (v *ServerList) AddServer(server *ServerSpec) { v.Lock() defer v.Unlock() v.servers = append(v.servers, server) } func (v *ServerList) Size() uint32 { v.RLock() defer v.RUnlock() return uint32(len(v.servers)) } func (v *ServerList) GetServer(idx uint32) *ServerSpec { v.RLock() defer v.RUnlock() for { if idx >= uint32(len(v.servers)) { return nil } server := v.servers[idx] if !server.IsValid() { v.RemoveServer(idx) continue } return server } } // Private: Visible for testing. func (v *ServerList) RemoveServer(idx uint32) { n := len(v.servers) v.servers[idx] = v.servers[n-1] v.servers = v.servers[:n-1] } type ServerPicker interface { PickServer() *ServerSpec } type RoundRobinServerPicker struct { sync.Mutex serverlist *ServerList nextIndex uint32 } func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker { return &RoundRobinServerPicker{ serverlist: serverlist, nextIndex: 0, } } func (v *RoundRobinServerPicker) PickServer() *ServerSpec { v.Lock() defer v.Unlock() next := v.nextIndex server := v.serverlist.GetServer(next) if server == nil { next = 0 server = v.serverlist.GetServer(0) } next++ if next >= v.serverlist.Size() { next = 0 } v.nextIndex = next return server }