update stopper

This commit is contained in:
Alex Grintsvayg 2018-05-24 13:05:05 -04:00
parent 315f8ff16c
commit 57a7c23787
10 changed files with 120 additions and 43 deletions

10
Gopkg.lock generated
View file

@ -152,7 +152,7 @@
"stopOnce", "stopOnce",
"util" "util"
] ]
revision = "a656ad8a1456310d6ca712098826d02950e46e0b" revision = "2a6ea528bdd66de4f3c707304e26f69dcf003909"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -172,6 +172,12 @@
packages = ["."] packages = ["."]
revision = "e2103e2c35297fb7e17febb81e49b312087a2372" revision = "e2103e2c35297fb7e17febb81e49b312087a2372"
[[projects]]
branch = "master"
name = "github.com/sebdah/goldie"
packages = ["."]
revision = "8784dd1ab561dcf43d141f6678e9e41f3d0dff55"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/sirupsen/logrus" name = "github.com/sirupsen/logrus"
@ -244,6 +250,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "b3d2f1578da4f4fca9a15d04df16cdb7f76f83c7916bab11fe1e50f65334a2c8" inputs-digest = "bfa7ee41b88f515ef386012a9dd28e045f9108de93c1dcfa66d9361340cf7eec"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View file

@ -3,13 +3,84 @@ package cluster
import ( import (
"io/ioutil" "io/ioutil"
baselog "log" baselog "log"
"os"
"os/signal"
"strconv"
"sync"
"syscall"
"github.com/davecgh/go-spew/spew"
"github.com/lbryio/lbry.go/crypto"
"github.com/lbryio/lbry.go/errors" "github.com/lbryio/lbry.go/errors"
"github.com/lbryio/reflector.go/cluster"
"github.com/hashicorp/serf/serf" "github.com/hashicorp/serf/serf"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type Cluster struct {
s *serf.Serf
eventCh <-chan serf.Event
}
func New() {
c := &Cluster{}
var err error
nodeName := crypto.RandString(12)
clusterAddr := "127.0.0.1:" + strconv.Itoa(clusterPort)
if args[0] == clusterStart {
c.s, c.eventCh, err = cluster.Connect(nodeName, clusterAddr, clusterPort)
} else {
c.s, c.eventCh, err = cluster.Connect(nodeName, clusterAddr, clusterPort+1+int(crypto.RandInt64(1000)))
}
if err != nil {
log.Fatal(err)
}
defer c.Leave()
shutdownCh := make(chan struct{})
var shutdownWg sync.WaitGroup
shutdownWg.Add(1)
go func() {
defer shutdownWg.Done()
for {
select {
case event := <-eventCh:
spew.Dump(event)
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 == nodeName {
// ignore event from my own joining of the cluster
} else {
//spew.Dump(c.Members())
alive := getAliveMembers(c.Members())
log.Printf("%s: my hash range is now %d of %d\n", nodeName, getHashRangeStart(nodeName, 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
}
}
case <-shutdownCh:
log.Debugln("shutting down event dumper")
return
}
}
}()
interruptChan := make(chan os.Signal, 1)
signal.Notify(interruptChan, os.Interrupt, syscall.SIGTERM)
<-interruptChan
log.Debugln("received interrupt")
close(shutdownCh)
log.Debugln("waiting for threads to finish")
shutdownWg.Wait()
log.Debugln("shutting down main thread")
}
func Connect(nodeName, addr string, port int) (*serf.Serf, <-chan serf.Event, error) { func Connect(nodeName, addr string, port int) (*serf.Serf, <-chan serf.Event, error) {
conf := serf.DefaultConfig() conf := serf.DefaultConfig()
conf.MemberlistConfig.BindPort = port conf.MemberlistConfig.BindPort = port

View file

@ -98,7 +98,7 @@ func uploadCmd(cmd *cobra.Command, args []string) {
for { for {
select { select {
case <-stopper.Chan(): case <-stopper.Ch():
return return
case filename, ok := <-filenameChan: case filename, ok := <-filenameChan:
if !ok { if !ok {
@ -113,7 +113,7 @@ func uploadCmd(cmd *cobra.Command, args []string) {
log.Errorf("worker %d: filename does not match hash (%s != %s), skipping", i, filename, hash) log.Errorf("worker %d: filename does not match hash (%s != %s), skipping", i, filename, hash)
select { select {
case countChan <- errInc: case countChan <- errInc:
case <-stopper.Chan(): case <-stopper.Ch():
} }
continue continue
} }
@ -123,14 +123,14 @@ func uploadCmd(cmd *cobra.Command, args []string) {
blobStore.PutSD(hash, blob) blobStore.PutSD(hash, blob)
select { select {
case countChan <- sdInc: case countChan <- sdInc:
case <-stopper.Chan(): case <-stopper.Ch():
} }
} else { } else {
log.Printf("worker %d: putting %s", i, hash) log.Printf("worker %d: putting %s", i, hash)
blobStore.Put(hash, blob) blobStore.Put(hash, blob)
select { select {
case countChan <- blobInc: case countChan <- blobInc:
case <-stopper.Chan(): case <-stopper.Ch():
} }
} }
} }
@ -143,7 +143,7 @@ func uploadCmd(cmd *cobra.Command, args []string) {
defer counterWG.Done() defer counterWG.Done()
for { for {
select { select {
case <-stopper.Chan(): case <-stopper.Ch():
return return
case countType, ok := <-countChan: case countType, ok := <-countChan:
if !ok { if !ok {
@ -172,7 +172,7 @@ Upload:
select { select {
case filenameChan <- filename: case filenameChan <- filename:
case <-stopper.Chan(): case <-stopper.Ch():
log.Warnln("Caught interrupt, quitting at first opportunity...") log.Warnln("Caught interrupt, quitting at first opportunity...")
break Upload break Upload
} }

View file

@ -10,6 +10,8 @@ import (
"github.com/lyoshenka/bencode" "github.com/lyoshenka/bencode"
) )
// TODO: http://roaringbitmap.org/
type Bitmap [nodeIDLength]byte type Bitmap [nodeIDLength]byte
func (b Bitmap) RawString() string { func (b Bitmap) RawString() string {

View file

@ -62,7 +62,7 @@ func (b *BootstrapNode) Connect(conn UDPConn) error {
select { select {
case <-t.C: case <-t.C:
b.check() b.check()
case <-b.stop.Chan(): case <-b.stop.Ch():
return return
} }
} }
@ -130,7 +130,7 @@ func (b *BootstrapNode) ping(c Contact) {
select { select {
case res = <-resCh: case res = <-resCh:
case <-b.stop.Chan(): case <-b.stop.Ch():
cancel() cancel()
return return
} }

View file

@ -81,8 +81,6 @@ type DHT struct {
node *Node node *Node
// stopper to shut down DHT // stopper to shut down DHT
stop *stopOnce.Stopper stop *stopOnce.Stopper
// wait group for all the things that need to be stopped when DHT shuts down
stopWG *sync.WaitGroup
// channel is closed when DHT joins network // channel is closed when DHT joins network
joined chan struct{} joined chan struct{}
// lock for announced list // lock for announced list
@ -107,7 +105,6 @@ func New(config *Config) (*DHT, error) {
contact: contact, contact: contact,
node: NewNode(contact.ID), node: NewNode(contact.ID),
stop: stopOnce.New(), stop: stopOnce.New(),
stopWG: &sync.WaitGroup{},
joined: make(chan struct{}), joined: make(chan struct{}),
lock: &sync.RWMutex{}, lock: &sync.RWMutex{},
announced: make(map[Bitmap]bool), announced: make(map[Bitmap]bool),
@ -143,6 +140,9 @@ func (dht *DHT) join() {
if err != nil { if err != nil {
log.Errorf("[%s] join: %s", dht.node.id.HexShort(), err.Error()) log.Errorf("[%s] join: %s", dht.node.id.HexShort(), err.Error())
} }
// TODO: after joining, refresh all the buckets all buckets further away than our closest neighbor
// http://xlattice.sourceforge.net/components/protocol/kademlia/specs.html#join
} }
// Start starts the dht // Start starts the dht
@ -176,7 +176,7 @@ func (dht *DHT) WaitUntilJoined() {
func (dht *DHT) Shutdown() { func (dht *DHT) Shutdown() {
log.Debugf("[%s] DHT shutting down", dht.node.id.HexShort()) log.Debugf("[%s] DHT shutting down", dht.node.id.HexShort())
dht.stop.Stop() dht.stop.Stop()
dht.stopWG.Wait() dht.stop.Wait()
dht.node.Shutdown() dht.node.Shutdown()
log.Debugf("[%s] DHT stopped", dht.node.id.HexShort()) log.Debugf("[%s] DHT stopped", dht.node.id.HexShort())
} }
@ -244,12 +244,12 @@ func (dht *DHT) Announce(hash Bitmap) error {
} }
func (dht *DHT) startReannouncer() { func (dht *DHT) startReannouncer() {
dht.stopWG.Add(1) dht.stop.Add(1)
defer dht.stopWG.Done() defer dht.stop.Done()
tick := time.NewTicker(tReannounce) tick := time.NewTicker(tReannounce)
for { for {
select { select {
case <-dht.stop.Chan(): case <-dht.stop.Ch():
return return
case <-tick.C: case <-tick.C:
dht.lock.RLock() dht.lock.RLock()
@ -262,8 +262,8 @@ func (dht *DHT) startReannouncer() {
} }
func (dht *DHT) storeOnNode(hash Bitmap, c Contact) { func (dht *DHT) storeOnNode(hash Bitmap, c Contact) {
dht.stopWG.Add(1) dht.stop.Add(1)
defer dht.stopWG.Done() defer dht.stop.Done()
// self-store // self-store
if dht.contact.Equals(c) { if dht.contact.Equals(c) {
@ -280,7 +280,7 @@ func (dht *DHT) storeOnNode(hash Bitmap, c Contact) {
select { select {
case res = <-resCh: case res = <-resCh:
case <-dht.stop.Chan(): case <-dht.stop.Ch():
cancel() cancel()
return return
} }
@ -304,7 +304,7 @@ func (dht *DHT) storeOnNode(hash Bitmap, c Contact) {
go func() { go func() {
select { select {
case <-resCh: case <-resCh:
case <-dht.stop.Chan(): case <-dht.stop.Ch():
cancel() cancel()
} }
}() }()

View file

@ -154,8 +154,8 @@ type storeArgsValue struct {
type storeArgs struct { type storeArgs struct {
BlobHash Bitmap BlobHash Bitmap
Value storeArgsValue Value storeArgsValue
NodeID Bitmap NodeID Bitmap // original publisher id? I think this is getting fixed in the new dht stuff
SelfStore bool // this is an int on the wire SelfStore bool // this is an int on the wire
} }
func (s storeArgs) MarshalBencode() ([]byte, error) { func (s storeArgs) MarshalBencode() ([]byte, error) {

View file

@ -87,7 +87,7 @@ func (n *Node) Connect(conn UDPConn) error {
// dht.PrintState() // dht.PrintState()
// select { // select {
// case <-t.C: // case <-t.C:
// case <-dht.stop.Chan(): // case <-dht.stop.Ch():
// return // return
// } // }
// } // }
@ -106,7 +106,7 @@ func (n *Node) Connect(conn UDPConn) error {
for { for {
select { select {
case <-n.stop.Chan(): case <-n.stop.Ch():
return return
default: default:
} }
@ -128,7 +128,7 @@ func (n *Node) Connect(conn UDPConn) error {
select { // needs select here because packet consumer can quit and the packets channel gets filled up and blocks select { // needs select here because packet consumer can quit and the packets channel gets filled up and blocks
case packets <- packet{data: data, raddr: raddr}: case packets <- packet{data: data, raddr: raddr}:
case <-n.stop.Chan(): case <-n.stop.Ch():
} }
} }
}() }()
@ -143,7 +143,7 @@ func (n *Node) Connect(conn UDPConn) error {
select { select {
case pkt = <-packets: case pkt = <-packets:
n.handlePacket(pkt) n.handlePacket(pkt)
case <-n.stop.Chan(): case <-n.stop.Ch():
return return
} }
} }
@ -434,8 +434,8 @@ func (n *Node) startRoutingTableGrooming() {
for { for {
select { select {
case <-refreshTicker.C: case <-refreshTicker.C:
RoutingTableRefresh(n, tRefresh, n.stop.Chan()) RoutingTableRefresh(n, tRefresh, n.stop.Ch())
case <-n.stop.Chan(): case <-n.stop.Ch():
return return
} }
} }

View file

@ -19,8 +19,7 @@ type contactFinder struct {
target Bitmap target Bitmap
node *Node node *Node
done *stopOnce.Stopper stop *stopOnce.Stopper
doneWG *sync.WaitGroup
findValueMutex *sync.Mutex findValueMutex *sync.Mutex
findValueResult []Contact findValueResult []Contact
@ -50,15 +49,14 @@ func newContactFinder(node *Node, target Bitmap, findValue bool) *contactFinder
activeContactsMutex: &sync.Mutex{}, activeContactsMutex: &sync.Mutex{},
shortlistMutex: &sync.Mutex{}, shortlistMutex: &sync.Mutex{},
shortlistAdded: make(map[Bitmap]bool), shortlistAdded: make(map[Bitmap]bool),
done: stopOnce.New(), stop: stopOnce.New(),
doneWG: &sync.WaitGroup{},
outstandingRequestsMutex: &sync.RWMutex{}, outstandingRequestsMutex: &sync.RWMutex{},
} }
} }
func (cf *contactFinder) Cancel() { func (cf *contactFinder) Cancel() {
cf.done.Stop() cf.stop.Stop()
cf.doneWG.Wait() cf.stop.Wait()
} }
func (cf *contactFinder) Find() (findNodeResponse, error) { func (cf *contactFinder) Find() (findNodeResponse, error) {
@ -73,14 +71,14 @@ func (cf *contactFinder) Find() (findNodeResponse, error) {
} }
for i := 0; i < alpha; i++ { for i := 0; i < alpha; i++ {
cf.doneWG.Add(1) cf.stop.Add(1)
go func(i int) { go func(i int) {
defer cf.doneWG.Done() defer cf.stop.Done()
cf.iterationWorker(i + 1) cf.iterationWorker(i + 1)
}(i) }(i)
} }
cf.doneWG.Wait() cf.stop.Wait()
// TODO: what to do if we have less than K active contacts, shortlist is empty, but we // TODO: what to do if we have less than K active contacts, shortlist is empty, but we
// TODO: have other contacts in our routing table whom we have not contacted. prolly contact them // TODO: have other contacts in our routing table whom we have not contacted. prolly contact them
@ -131,7 +129,7 @@ func (cf *contactFinder) iterationWorker(num int) {
resCh, cancel := cf.node.SendCancelable(contact, req) resCh, cancel := cf.node.SendCancelable(contact, req)
select { select {
case res = <-resCh: case res = <-resCh:
case <-cf.done.Chan(): case <-cf.stop.Ch():
log.Debugf("[%s] worker %d: canceled", cf.node.id.HexShort(), num) log.Debugf("[%s] worker %d: canceled", cf.node.id.HexShort(), num)
cancel() cancel()
return return
@ -145,7 +143,7 @@ func (cf *contactFinder) iterationWorker(num int) {
cf.findValueMutex.Lock() cf.findValueMutex.Lock()
cf.findValueResult = res.Contacts cf.findValueResult = res.Contacts
cf.findValueMutex.Unlock() cf.findValueMutex.Unlock()
cf.done.Stop() cf.stop.Stop()
return return
} else { } else {
log.Debugf("[%s] worker %d: got contacts", cf.node.id.HexShort(), num) log.Debugf("[%s] worker %d: got contacts", cf.node.id.HexShort(), num)
@ -158,7 +156,7 @@ func (cf *contactFinder) iterationWorker(num int) {
if cf.isSearchFinished() { if cf.isSearchFinished() {
log.Debugf("[%s] worker %d: search is finished", cf.node.id.HexShort(), num) log.Debugf("[%s] worker %d: search is finished", cf.node.id.HexShort(), num)
cf.done.Stop() cf.stop.Stop()
return return
} }
} }
@ -214,7 +212,7 @@ func (cf *contactFinder) isSearchFinished() bool {
} }
select { select {
case <-cf.done.Chan(): case <-cf.stop.Ch():
return true return true
default: default:
} }

View file

@ -37,7 +37,7 @@ func (tm *tokenManager) Start(interval time.Duration) {
select { select {
case <-tick.C: case <-tick.C:
tm.rotateSecret() tm.rotateSecret()
case <-tm.done.Chan(): case <-tm.done.Ch():
return return
} }
} }