featurebase/client/cluster.go
Samir Patel 17e8dbd318 client side retry ingestAPI requests on primary host
If non-primary host fails to process a request, retry on primary node.

conditions when we should not do this:
- no error
- we've aleady tried the primary
- we're making a status request to get the primary node...this
  could lead to lock contention if we allow it to happen as we are
  making an http request within an on going http request to discover
  the primary node.

This also deletes the RemoveHost method and the associated test b/c
it is not used anywhere anymore and updates the returned error type.
2022-03-10 10:22:13 -06:00

87 lines
1.8 KiB
Go

// Copyright 2021 Molecula Corp. All rights reserved.
// package ctl contains all pilosa subcommands other than 'server'. These are
// generally administration, testing, and debugging tools.
package client
import (
"sync"
pnet "github.com/molecula/featurebase/v3/net"
)
// Cluster contains hosts in a Pilosa cluster.
type Cluster struct {
hosts []*pnet.URI
okList []bool
mutex *sync.RWMutex
lastHostIdx int
}
// DefaultCluster returns the default Cluster.
func DefaultCluster() *Cluster {
return &Cluster{
hosts: make([]*pnet.URI, 0),
okList: make([]bool, 0),
mutex: &sync.RWMutex{},
}
}
// NewClusterWithHost returns a cluster with the given URIs.
func NewClusterWithHost(hosts ...*pnet.URI) *Cluster {
cluster := DefaultCluster()
for _, host := range hosts {
cluster.AddHost(host)
}
return cluster
}
// AddHost adds a host to the cluster.
func (c *Cluster) AddHost(address *pnet.URI) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.hosts = append(c.hosts, address)
c.okList = append(c.okList, true)
}
// Host returns a host in the cluster.
func (c *Cluster) Host() *pnet.URI {
c.mutex.Lock()
var host *pnet.URI
for i := range c.okList {
idx := (i + c.lastHostIdx) % len(c.okList)
ok := c.okList[idx]
if ok {
host = c.hosts[idx]
break
}
}
c.lastHostIdx++
c.mutex.Unlock()
if host != nil {
return host
}
c.reset()
return host
}
// Hosts returns all available hosts in the cluster.
func (c *Cluster) Hosts() []pnet.URI {
c.mutex.RLock()
defer c.mutex.RUnlock()
hosts := make([]pnet.URI, 0, len(c.hosts))
for i, host := range c.hosts {
if c.okList[i] {
hosts = append(hosts, *host)
}
}
return hosts
}
func (c *Cluster) reset() {
c.mutex.Lock()
defer c.mutex.Unlock()
for i := range c.okList {
c.okList[i] = true
}
}