reflector.go/cluster/cluster.go
2018-05-29 17:33:58 -04:00

129 lines
2.7 KiB
Go

package cluster
import (
"io/ioutil"
baselog "log"
"sort"
"github.com/lbryio/lbry.go/crypto"
"github.com/lbryio/lbry.go/errors"
"github.com/lbryio/lbry.go/stopOnce"
"github.com/hashicorp/serf/serf"
log "github.com/sirupsen/logrus"
)
const (
DefaultClusterPort = 17946
)
type Cluster struct {
name string
port int
seedAddr string
s *serf.Serf
eventCh chan serf.Event
stop *stopOnce.Stopper
}
func New(port int, seedAddr string) *Cluster {
return &Cluster{
name: crypto.RandString(12),
port: port,
seedAddr: seedAddr,
stop: stopOnce.New(),
}
}
func (c *Cluster) Connect() error {
var err error
conf := serf.DefaultConfig()
conf.MemberlistConfig.BindPort = c.port
conf.MemberlistConfig.AdvertisePort = c.port
conf.NodeName = c.name
nullLogger := baselog.New(ioutil.Discard, "", 0)
conf.Logger = nullLogger
c.eventCh = make(chan serf.Event)
conf.EventCh = c.eventCh
c.s, err = serf.Create(conf)
if err != nil {
return errors.Prefix("couldn't create cluster", err)
}
if c.seedAddr != "" {
_, err = c.s.Join([]string{c.seedAddr}, true)
if err != nil {
return err
}
}
c.listen()
return nil
}
func (c *Cluster) Shutdown() {
c.stop.StopAndWait()
c.s.Leave()
}
func (c *Cluster) listen() {
c.stop.Add(1)
go func() {
defer c.stop.Done()
for {
select {
case <-c.stop.Ch():
return
case event := <-c.eventCh:
switch event.EventType() {
case serf.EventMemberJoin, serf.EventMemberFailed, serf.EventMemberLeave:
memberEvent := event.(serf.MemberEvent)
if event.EventType() == serf.EventMemberJoin && len(memberEvent.Members) == 1 && memberEvent.Members[0].Name == c.name {
// ignore event from my own joining of the cluster
continue
}
//spew.Dump(c.Members())
alive := getAliveMembers(c.s.Members())
log.Printf("%s: my hash range is now %d of %d\n", c.name, getHashRangeStart(c.name, alive), len(alive))
// figure out my new hash range based on the start and the number of alive members
// get hashes in that range that need announcing
// announce them
// if more than one node is announcing each hash, figure out how to deal with last_announced_at so both nodes dont announce the same thing at the same time
}
}
}
}()
}
func getHashRangeStart(myName string, members []serf.Member) int {
var names []string
for _, m := range members {
names = append(names, m.Name)
}
sort.Strings(names)
i := 1
for _, n := range names {
if n == myName {
return i
}
i++
}
return -1
}
func getAliveMembers(members []serf.Member) []serf.Member {
var alive []serf.Member
for _, m := range members {
if m.Status == serf.StatusAlive {
alive = append(alive, m)
}
}
return alive
}