From 5dde733d0c1d620a29197b58b312eaf5ace7ef3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 29 Apr 2015 18:42:43 +0300 Subject: [PATCH] p2p: add a dialer cooldown to prevent reattempting failures --- p2p/peer_error.go | 2 ++ p2p/server.go | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/p2p/peer_error.go b/p2p/peer_error.go index a912f60644..d9c09a9c6c 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -73,6 +73,7 @@ const ( DiscSelf DiscReadTimeout DiscSubprotocolError + DiscFailureCooldown ) var discReasonToString = [...]string{ @@ -89,6 +90,7 @@ var discReasonToString = [...]string{ DiscSelf: "Connected to self", DiscReadTimeout: "Read timeout", DiscSubprotocolError: "Subprotocol error", + DiscFailureCooldown: "Failure cooldown", } func (d DiscReason) String() string { diff --git a/p2p/server.go b/p2p/server.go index 794c361256..1f15ca2011 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -21,6 +21,7 @@ const ( defaultDialTimeout = 10 * time.Second refreshPeersInterval = 30 * time.Second trustedPeerCheckInterval = 15 * time.Second + dialFailureCooldown = 30 * time.Second // This is the maximum number of inbound connection // that are allowed to linger between 'accepted' and @@ -100,9 +101,11 @@ type Server struct { ourHandshake *protoHandshake - lock sync.RWMutex // protects running and peers + lock sync.RWMutex // protects running and peers + running bool - peers map[discover.NodeID]*Peer + peers map[discover.NodeID]*Peer // Currently active peer pool + fails map[discover.NodeID]bool // List of recently failed connections trusts map[discover.NodeID]*discover.Node // Map of currently trusted remote nodes trustDial chan *discover.Node // Dial request channel reserved for the trusted nodes @@ -201,6 +204,7 @@ func (srv *Server) Start() (err error) { } srv.quit = make(chan struct{}) srv.peers = make(map[discover.NodeID]*Peer) + srv.fails = make(map[discover.NodeID]bool) // Create the current trust map, and the associated dialing channel srv.trusts = make(map[discover.NodeID]*discover.Node) @@ -456,7 +460,20 @@ func (srv *Server) dialNode(dest *discover.Node) { // dialNode, so we need to count it down again. startPeer also // does that when an error occurs. srv.peerWG.Done() - glog.V(logger.Detail).Infof("dial error: %v", err) + + // Mark the dialing as failed so prevent too fast redials, and set a + // timer for re-allowing dialing + srv.lock.Lock() + srv.fails[dest.ID] = true + srv.lock.Unlock() + go func() { + glog.V(logger.Detail).Infof("Dialing %v failed: %v. Locked until %v\n", dest, err, time.Now().Add(dialFailureCooldown)) + <-time.After(dialFailureCooldown) + + srv.lock.Lock() + delete(srv.fails, dest.ID) + srv.lock.Unlock() + }() return } srv.startPeer(conn, dest) @@ -546,6 +563,9 @@ func (srv *Server) checkPeer(id discover.NodeID) (bool, DiscReason) { case id == srv.ntab.Self().ID: return false, DiscSelf + case srv.fails[id]: + return false, DiscFailureCooldown + default: return true, 0 }