Merge branch '23_retry_peers' of https://github.com/bboreham/weave into 23_retry_peers

This commit is contained in:
Bryan Boreham committed 2014-09-08 17:35:05 +01:00
commit 924ebc0d88
5 files changed
+67 -48

No files matched your search

+3 -3
View File
@@ -221,6 +221,7 @@ func (conn *LocalConnection) handleSetEstablished() error {
conn.established = true
conn.Unlock()
if !old {
conn.Router.ConnectionMaker.ConnectionEstablished(conn.remoteTCPAddr)
conn.local.ConnectionEstablished(conn)
if err := conn.ensureHeartbeat(false); err != nil {
return err
@@ -345,8 +346,8 @@ func (conn *LocalConnection) handshake(acceptNewPeer bool) error {
return err
}
if !acceptNewPeer {
if _, found := conn.Router.Peers.Fetch(name); !found {
return fmt.Errorf("Found unknown remote name: %s at %s", name, conn.remoteTCPAddr)
if _, found := conn.Router.Peers.Fetch(name); !found {
return fmt.Errorf("Found unknown remote name: %s at %s", name, conn.remoteTCPAddr)
}
}
@@ -447,7 +448,6 @@ func (conn *LocalConnection) receiveTCP(decoder *gob.Decoder, usingPassword bool
// them and thus has informed us via TCP that it considers
// the connection is now up. We now do a fetchAll on it.
conn.SetEstablished()
conn.Router.ConnectionMaker.ConnectionEstablished(conn.remoteTCPAddr)
conn.SendTCP(ProtocolFetchAllByte)
} else if msg[0] == ProtocolStartFragmentationTest {
conn.Forward(false, &ForwardedFrame{
+51 -33
View File
@@ -10,29 +10,34 @@ import (
)
const (
InitialInterval = 1 * time.Second
InitialInterval = 5 * time.Second
MaxInterval = 10 * time.Minute
MaxAttemptCount = 100
CMEnsure = iota
CMStatus = iota
CMEstablished = iota
CMConnSucceeded = iota
CMConnFailed = iota
)
const (
CMUnconnected ConnectionState = iota
CMAttempting = iota
CMEstablishedState = iota
)
func StartConnectionMaker(router *Router) *ConnectionMaker {
queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
state := &ConnectionMaker{
router: router,
queryChan: queryChan,
targets: make(map[string]*Target)}
router: router,
queryChan: queryChan,
targets: make(map[string]*Target)}
go state.queryLoop(queryChan)
return state
}
func (cm *ConnectionMaker) InitiateConnection(address string) {
cm.queryChan <- &ConnectionMakerInteraction{
Interaction: Interaction{code: CMEnsure},
Interaction: Interaction{code: CMEnsure},
acceptAnyPeer: true,
address: address}
}
@@ -43,9 +48,9 @@ func (cm *ConnectionMaker) EnsureConnection(address string) {
address = addrHost
}
cm.queryChan <- &ConnectionMakerInteraction{
Interaction: Interaction{code: CMEnsure},
Interaction: Interaction{code: CMEnsure},
acceptAnyPeer: false,
address: address}
address: address}
}
func (cm *ConnectionMaker) ConnectionEstablished(address string) {
@@ -74,6 +79,11 @@ func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteractio
tick = time.After(5 * time.Second)
}
}
tickNow := func() {
if tick == nil {
tick = time.After(0 * time.Second)
}
}
for {
select {
case query, ok := <-queryChan:
@@ -83,32 +93,30 @@ func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteractio
switch {
case query.code == CMEnsure:
cm.addToTargets(query.acceptAnyPeer, query.address)
maybeTick()
cm.resetTarget(query.address)
tickNow()
case query.code == CMStatus:
query.resultChan <- cm.status()
case query.code == CMEstablished:
target := cm.targets[query.address]
log.Println("Connection established to", query.address, target)
if target != nil {
target.established = true
target.state = CMEstablishedState
} else {
log.Fatal("Connection established to unknown address", query.address)
}
case query.code == CMConnSucceeded:
cm.targets[query.address].attempting = false
case query.code == CMConnFailed:
target := cm.targets[query.address]
target.attempting = false
after, interval := tryAfter(target.tryInterval)
target.tryInterval = interval
target.tryAfter = after
target.state = CMUnconnected
target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
maybeTick()
default:
log.Fatal("Unexpected connection maker query:", query)
}
case now := <-tick:
for address, target := range cm.targets {
if !target.established && !target.attempting && now.After(target.tryAfter) {
if target.state == CMUnconnected && now.After(target.tryAfter) {
target.attemptCount += 1
target.attempting = true;
target.state = CMAttempting
go cm.attemptConnection(address, target.acceptAnyPeer)
}
}
@@ -121,23 +129,31 @@ func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteractio
func (cm *ConnectionMaker) addToTargets(acceptAnyPeer bool, address string) {
target := cm.targets[address]
if target == nil {
after, interval := tryAfter(InitialInterval)
target = &Target{
state: CMUnconnected,
acceptAnyPeer: acceptAnyPeer,
tryInterval: interval,
tryAfter: after}
}
cm.targets[address] = target
}
target.established = false // this seems a crap place to do this
// FIXME: what does it mean if an address is added twice?
cm.targets[address] = target
}
func (cm *ConnectionMaker) resetTarget(address string) {
target := cm.targets[address]
// If we were in the middle of a connection attempt then back-off again
if target.state == CMAttempting {
target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
} else {
target.tryAfter, target.tryInterval = tryImmediately()
}
target.state = CMUnconnected
}
func (cm *ConnectionMaker) status() string {
var buf bytes.Buffer
for address, target := range cm.targets {
if (target.established) {
if target.state == CMEstablishedState {
buf.WriteString(fmt.Sprintf("%s connected\n", address))
} else if target.attempting {
} else if target.state == CMAttempting {
buf.WriteString(fmt.Sprintf("%s (%v attempts, trying since %v)\n", address, target.attemptCount, target.tryAfter))
} else {
buf.WriteString(fmt.Sprintf("%s (%v attempts, next at %v)\n", address, target.attemptCount, target.tryAfter))
@@ -148,15 +164,17 @@ func (cm *ConnectionMaker) status() string {
func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
log.Println("Attempting connection to", address)
var conncode = CMConnSucceeded
if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
log.Println(err)
conncode = CMConnFailed
cm.queryChan <- &ConnectionMakerInteraction{
Interaction: Interaction{code: CMConnFailed},
address: address}
}
// Tell the query loop we've finished this attempt
cm.queryChan <- &ConnectionMakerInteraction{
Interaction: Interaction{code: conncode},
address: address}
}
func tryImmediately() (time.Time, time.Duration) {
interval := time.Duration(rand.Int63n(int64(InitialInterval)))
return time.Now(), interval
}
func tryAfter(interval time.Duration) (time.Time, time.Duration) {
+1
View File
@@ -115,6 +115,7 @@ func (peer *Peer) SetVersionAndConnections(version uint64, connections map[PeerN
}
}
}
func (peer *Peer) Forward(dstPeer *Peer, df bool, frame []byte, dec *EthernetDecoder) error {
return peer.Relay(peer, dstPeer, df, frame, dec)
}
+10 -9
View File
@@ -160,19 +160,20 @@ type ConnectionMakerInteraction struct {
}
type ConnectionMaker struct {
router *Router
queryChan chan<- *ConnectionMakerInteraction
targets map[string]*Target
router *Router
queryChan chan<- *ConnectionMakerInteraction
targets map[string]*Target
}
type ConnectionState int
// Information about an address where we may find a peer
type Target struct {
acceptAnyPeer bool // was this address given to us on the command line?
attempting bool // are we currently attempting to connect to this address?
established bool // has the connection been established
tryAfter time.Time // next time to try this address
tryInterval time.Duration // backoff time on next failure
attemptCount int
acceptAnyPeer bool // was this address given to us on the command line?
state ConnectionState
tryAfter time.Time // next time to try this address
tryInterval time.Duration // backoff time on next failure
attemptCount int
}
// UDPSender interface and implementations
+2 -3
View File
@@ -1,13 +1,13 @@
package main
import (
"github.com/zettio/weave"
"code.google.com/p/gopacket/layers"
"crypto/sha256"
"flag"
"fmt"
"io"
"github.com/davecheney/profile"
"github.com/zettio/weave"
"io"
"log"
"net"
"net/http"
@@ -141,7 +141,6 @@ func handleHttp(router *weave.Router) {
}
}
func handleSignals(router *weave.Router) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT, syscall.SIGUSR1)