aboutsummaryrefslogtreecommitdiffstats
path: root/p2p
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2015-08-17 17:27:41 +0800
committerFelix Lange <fjl@twurst.com>2015-08-19 20:57:16 +0800
commitdd54fef89888372ab5961c1b5a6ac917fc47d49c (patch)
tree83cf697002fd089f3642e88732930b38ebaa5e7c /p2p
parentedccc7ae3430836141b803c252f26bf1ef98d185 (diff)
downloaddexon-dd54fef89888372ab5961c1b5a6ac917fc47d49c.tar.gz
dexon-dd54fef89888372ab5961c1b5a6ac917fc47d49c.tar.zst
dexon-dd54fef89888372ab5961c1b5a6ac917fc47d49c.zip
p2p/discover: don't attempt to replace nodes that are being replaced
PR #1621 changed Table locking so the mutex is not held while a contested node is being pinged. If multiple nodes ping the local node during this time window, multiple ping packets will be sent to the contested node. The changes in this commit prevent multiple packets by tracking whether the node is being replaced.
Diffstat (limited to 'p2p')
-rw-r--r--p2p/discover/node.go4
-rw-r--r--p2p/discover/table.go15
2 files changed, 15 insertions, 4 deletions
diff --git a/p2p/discover/node.go b/p2p/discover/node.go
index b6956e197..a14f29424 100644
--- a/p2p/discover/node.go
+++ b/p2p/discover/node.go
@@ -48,6 +48,10 @@ type Node struct {
// In those tests, the content of sha will not actually correspond
// with ID.
sha common.Hash
+
+ // whether this node is currently being pinged in order to replace
+ // it in a bucket
+ contested bool
}
func newNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node {
diff --git a/p2p/discover/table.go b/p2p/discover/table.go
index b077f010c..972bc1077 100644
--- a/p2p/discover/table.go
+++ b/p2p/discover/table.go
@@ -455,24 +455,31 @@ func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error {
func (tab *Table) add(new *Node) {
b := tab.buckets[logdist(tab.self.sha, new.sha)]
tab.mutex.Lock()
+ defer tab.mutex.Unlock()
if b.bump(new) {
- tab.mutex.Unlock()
return
}
var oldest *Node
if len(b.entries) == bucketSize {
oldest = b.entries[bucketSize-1]
+ if oldest.contested {
+ // The node is already being replaced, don't attempt
+ // to replace it.
+ return
+ }
+ oldest.contested = true
// Let go of the mutex so other goroutines can access
// the table while we ping the least recently active node.
tab.mutex.Unlock()
- if err := tab.ping(oldest.ID, oldest.addr()); err == nil {
+ err := tab.ping(oldest.ID, oldest.addr())
+ tab.mutex.Lock()
+ oldest.contested = false
+ if err == nil {
// The node responded, don't replace it.
return
}
- tab.mutex.Lock()
}
added := b.replace(new, oldest)
- tab.mutex.Unlock()
if added && tab.nodeAddedHook != nil {
tab.nodeAddedHook(new)
}