Limit the upper bounds of how many pending peers we track (#1714)
This commit is contained in:
parent
baa0767c26
commit
58fc7e45db
|
@ -24,6 +24,10 @@ const (
|
||||||
// to get the maximum number of cached peers allowed.
|
// to get the maximum number of cached peers allowed.
|
||||||
var maxCachedPeersMultiplier = 1
|
var maxCachedPeersMultiplier = 1
|
||||||
|
|
||||||
|
// maxPendingPeersMultiplier peers max limit will be multiplied by this number
|
||||||
|
// to get the maximum number of pending peers allowed.
|
||||||
|
var maxPendingPeersMultiplier = 2
|
||||||
|
|
||||||
// TopicPoolInterface the TopicPool interface.
|
// TopicPoolInterface the TopicPool interface.
|
||||||
type TopicPoolInterface interface {
|
type TopicPoolInterface interface {
|
||||||
StopSearch(server *p2p.Server)
|
StopSearch(server *p2p.Server)
|
||||||
|
@ -52,9 +56,11 @@ func newTopicPool(discovery discovery.Discovery, topic discv5.Topic, limits para
|
||||||
fastModeTimeout: DefaultTopicFastModeTimeout,
|
fastModeTimeout: DefaultTopicFastModeTimeout,
|
||||||
pendingPeers: make(map[enode.ID]*peerInfoItem),
|
pendingPeers: make(map[enode.ID]*peerInfoItem),
|
||||||
discoveredPeersQueue: make(peerPriorityQueue, 0),
|
discoveredPeersQueue: make(peerPriorityQueue, 0),
|
||||||
|
discoveredPeers: make(map[enode.ID]bool),
|
||||||
connectedPeers: make(map[enode.ID]*peerInfo),
|
connectedPeers: make(map[enode.ID]*peerInfo),
|
||||||
cache: cache,
|
cache: cache,
|
||||||
maxCachedPeers: limits.Max * maxCachedPeersMultiplier,
|
maxCachedPeers: limits.Max * maxCachedPeersMultiplier,
|
||||||
|
maxPendingPeers: limits.Max * maxPendingPeersMultiplier,
|
||||||
}
|
}
|
||||||
heap.Init(&pool.discoveredPeersQueue)
|
heap.Init(&pool.discoveredPeersQueue)
|
||||||
|
|
||||||
|
@ -85,12 +91,14 @@ type TopicPool struct {
|
||||||
|
|
||||||
pendingPeers map[enode.ID]*peerInfoItem // contains found and requested to be connected peers but not confirmed
|
pendingPeers map[enode.ID]*peerInfoItem // contains found and requested to be connected peers but not confirmed
|
||||||
discoveredPeersQueue peerPriorityQueue // priority queue to find the most recently discovered peers; does not containt peers requested to connect
|
discoveredPeersQueue peerPriorityQueue // priority queue to find the most recently discovered peers; does not containt peers requested to connect
|
||||||
|
discoveredPeers map[enode.ID]bool // remembers which peers have already been discovered and are enqueued
|
||||||
connectedPeers map[enode.ID]*peerInfo // currently connected peers
|
connectedPeers map[enode.ID]*peerInfo // currently connected peers
|
||||||
|
|
||||||
stopSearchTimeout *time.Time
|
stopSearchTimeout *time.Time
|
||||||
|
|
||||||
maxCachedPeers int
|
maxPendingPeers int
|
||||||
cache *Cache
|
maxCachedPeers int
|
||||||
|
cache *Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TopicPool) addToPendingPeers(peer *peerInfo) {
|
func (t *TopicPool) addToPendingPeers(peer *peerInfo) {
|
||||||
|
@ -101,12 +109,33 @@ func (t *TopicPool) addToPendingPeers(peer *peerInfo) {
|
||||||
peerInfo: peer,
|
peerInfo: peer,
|
||||||
index: notQueuedIndex,
|
index: notQueuedIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maxPendingPeers = 0 means no limits.
|
||||||
|
if t.maxPendingPeers == 0 || t.maxPendingPeers >= len(t.pendingPeers) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldestPeer *peerInfo
|
||||||
|
for _, i := range t.pendingPeers {
|
||||||
|
if oldestPeer != nil && oldestPeer.discoveredTime < i.peerInfo.discoveredTime {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
oldestPeer = i.peerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
t.removeFromPendingPeers(oldestPeer.NodeID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// addToQueue adds the passed peer to the queue if it is already pending.
|
// addToQueue adds the passed peer to the queue if it is already pending.
|
||||||
func (t *TopicPool) addToQueue(peer *peerInfo) {
|
func (t *TopicPool) addToQueue(peer *peerInfo) {
|
||||||
if p, ok := t.pendingPeers[peer.NodeID()]; ok {
|
if p, ok := t.pendingPeers[peer.NodeID()]; ok {
|
||||||
|
if _, ok := t.discoveredPeers[peer.NodeID()]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
heap.Push(&t.discoveredPeersQueue, p)
|
heap.Push(&t.discoveredPeersQueue, p)
|
||||||
|
t.discoveredPeers[peer.NodeID()] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +145,7 @@ func (t *TopicPool) popFromQueue() *peerInfo {
|
||||||
}
|
}
|
||||||
item := heap.Pop(&t.discoveredPeersQueue).(*peerInfoItem)
|
item := heap.Pop(&t.discoveredPeersQueue).(*peerInfoItem)
|
||||||
item.index = notQueuedIndex
|
item.index = notQueuedIndex
|
||||||
|
delete(t.discoveredPeers, item.peerInfo.NodeID())
|
||||||
return item.peerInfo
|
return item.peerInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +157,7 @@ func (t *TopicPool) removeFromPendingPeers(nodeID enode.ID) {
|
||||||
delete(t.pendingPeers, nodeID)
|
delete(t.pendingPeers, nodeID)
|
||||||
if peer.index != notQueuedIndex {
|
if peer.index != notQueuedIndex {
|
||||||
heap.Remove(&t.discoveredPeersQueue, peer.index)
|
heap.Remove(&t.discoveredPeersQueue, peer.index)
|
||||||
|
delete(t.discoveredPeers, nodeID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
@ -340,6 +341,63 @@ func (s *TopicPoolSuite) TestMaxCachedPeers() {
|
||||||
s.Equal(3, len(cached))
|
s.Equal(3, len(cached))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TopicPoolSuite) TestMaxPendingPeers() {
|
||||||
|
s.topicPool.maxPendingPeers = 2
|
||||||
|
|
||||||
|
nodeID1, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
|
||||||
|
nodeID2, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
|
||||||
|
nodeID3, peer3 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
|
||||||
|
pk1, _ := peer1.ID.Pubkey()
|
||||||
|
pk2, _ := peer2.ID.Pubkey()
|
||||||
|
pk3, _ := peer3.ID.Pubkey()
|
||||||
|
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer1, publicKey: pk1})
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer2, publicKey: pk2})
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer3, publicKey: pk3})
|
||||||
|
|
||||||
|
s.Equal(2, len(s.topicPool.pendingPeers))
|
||||||
|
s.Require().NotContains(s.topicPool.pendingPeers, nodeID1)
|
||||||
|
s.Require().Contains(s.topicPool.pendingPeers, nodeID2)
|
||||||
|
s.Require().Contains(s.topicPool.pendingPeers, nodeID3)
|
||||||
|
|
||||||
|
// maxPendingPeers = 0 means no limits.
|
||||||
|
s.topicPool.maxPendingPeers = 0
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer1, publicKey: pk1})
|
||||||
|
|
||||||
|
s.Equal(3, len(s.topicPool.pendingPeers))
|
||||||
|
s.Require().Contains(s.topicPool.pendingPeers, nodeID1)
|
||||||
|
s.Require().Contains(s.topicPool.pendingPeers, nodeID2)
|
||||||
|
s.Require().Contains(s.topicPool.pendingPeers, nodeID3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TopicPoolSuite) TestQueueDuplicatePeers() {
|
||||||
|
_, peer1 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
|
||||||
|
_, peer2 := s.createDiscV5Node(s.peer.Self().IP(), 32311)
|
||||||
|
pk1, _ := peer1.ID.Pubkey()
|
||||||
|
pk2, _ := peer2.ID.Pubkey()
|
||||||
|
peerInfo1 := &peerInfo{discoveredTime: mclock.Now(), node: peer1, publicKey: pk1}
|
||||||
|
peerInfo2 := &peerInfo{discoveredTime: mclock.Now(), node: peer2, publicKey: pk2}
|
||||||
|
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer1, publicKey: pk1})
|
||||||
|
s.topicPool.addToPendingPeers(&peerInfo{discoveredTime: mclock.Now(), node: peer2, publicKey: pk2})
|
||||||
|
s.topicPool.addToQueue(peerInfo1)
|
||||||
|
s.topicPool.addToQueue(peerInfo2)
|
||||||
|
|
||||||
|
s.Equal(2, len(s.topicPool.discoveredPeersQueue))
|
||||||
|
s.Equal(2, len(s.topicPool.discoveredPeers))
|
||||||
|
|
||||||
|
s.topicPool.addToQueue(peerInfo1)
|
||||||
|
|
||||||
|
s.Equal(2, len(s.topicPool.discoveredPeersQueue))
|
||||||
|
s.Equal(2, len(s.topicPool.discoveredPeers))
|
||||||
|
|
||||||
|
peer := s.topicPool.popFromQueue()
|
||||||
|
|
||||||
|
s.Equal(1, len(s.topicPool.discoveredPeersQueue))
|
||||||
|
s.Equal(1, len(s.topicPool.discoveredPeers))
|
||||||
|
s.Require().NotContains(s.topicPool.discoveredPeers, peer.NodeID())
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TopicPoolSuite) TestNewTopicPoolInterface() {
|
func (s *TopicPoolSuite) TestNewTopicPoolInterface() {
|
||||||
limits := params.NewLimits(1, 2)
|
limits := params.NewLimits(1, 2)
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
|
|
Loading…
Reference in New Issue