mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-27 05:30:43 +00:00
Fix PeerPool issue with peers overflow maxPeers setting. (#1285)
This commit is contained in:
parent
0f55ab13e8
commit
293d990d43
@ -8,6 +8,9 @@ type
|
|||||||
PeerFlags = enum
|
PeerFlags = enum
|
||||||
Acquired, DeleteOnRelease
|
Acquired, DeleteOnRelease
|
||||||
|
|
||||||
|
EventType = enum
|
||||||
|
NotEmptyEvent, NotFullEvent
|
||||||
|
|
||||||
PeerItem[T] = object
|
PeerItem[T] = object
|
||||||
data: T
|
data: T
|
||||||
peerType: PeerType
|
peerType: PeerType
|
||||||
@ -62,21 +65,35 @@ iterator pairs*[A, B](pool: PeerPool[A, B]): (B, A) =
|
|||||||
for peerId, peerIdx in pool.registry:
|
for peerId, peerIdx in pool.registry:
|
||||||
yield (peerId, pool.storage[peerIdx.data].data)
|
yield (peerId, pool.storage[peerIdx.data].data)
|
||||||
|
|
||||||
proc waitNotEmptyEvent[A, B](pool: PeerPool[A, B],
|
template incomingEvent(eventType: EventType): AsyncEvent =
|
||||||
|
case eventType
|
||||||
|
of EventType.NotEmptyEvent:
|
||||||
|
pool.incNotEmptyEvent
|
||||||
|
of EventType.NotFullEvent:
|
||||||
|
pool.incNotFullEvent
|
||||||
|
|
||||||
|
template outgoingEvent(eventType: EventType): AsyncEvent =
|
||||||
|
case eventType
|
||||||
|
of EventType.NotEmptyEvent:
|
||||||
|
pool.outNotEmptyEvent
|
||||||
|
of EventType.NotFullEvent:
|
||||||
|
pool.outNotFullEvent
|
||||||
|
|
||||||
|
proc waitForEvent[A, B](pool: PeerPool[A, B], eventType: EventType,
|
||||||
filter: set[PeerType]) {.async.} =
|
filter: set[PeerType]) {.async.} =
|
||||||
if filter == {PeerType.Incoming, PeerType.Outgoing} or filter == {}:
|
if filter == {PeerType.Incoming, PeerType.Outgoing} or filter == {}:
|
||||||
var fut1 = pool.incNotEmptyEvent.wait()
|
var fut1 = incomingEvent(eventType).wait()
|
||||||
var fut2 = pool.outNotEmptyEvent.wait()
|
var fut2 = outgoingEvent(eventType).wait()
|
||||||
try:
|
try:
|
||||||
discard await one(fut1, fut2)
|
discard await one(fut1, fut2)
|
||||||
if fut1.finished:
|
if fut1.finished:
|
||||||
if not(fut2.finished):
|
if not(fut2.finished):
|
||||||
fut2.cancel()
|
fut2.cancel()
|
||||||
pool.incNotEmptyEvent.clear()
|
incomingEvent(eventType).clear()
|
||||||
else:
|
else:
|
||||||
if not(fut1.finished):
|
if not(fut1.finished):
|
||||||
fut1.cancel()
|
fut1.cancel()
|
||||||
pool.outNotEmptyEvent.clear()
|
outgoingEvent(eventType).clear()
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
if not(fut1.finished):
|
if not(fut1.finished):
|
||||||
fut1.cancel()
|
fut1.cancel()
|
||||||
@ -84,20 +101,19 @@ proc waitNotEmptyEvent[A, B](pool: PeerPool[A, B],
|
|||||||
fut2.cancel()
|
fut2.cancel()
|
||||||
raise
|
raise
|
||||||
elif PeerType.Incoming in filter:
|
elif PeerType.Incoming in filter:
|
||||||
await pool.incNotEmptyEvent.wait()
|
await incomingEvent(eventType).wait()
|
||||||
pool.incNotEmptyEvent.clear()
|
incomingEvent(eventType).clear()
|
||||||
elif PeerType.Outgoing in filter:
|
elif PeerType.Outgoing in filter:
|
||||||
await pool.outNotEmptyEvent.wait()
|
await outgoingEvent(eventType).wait()
|
||||||
pool.outNotEmptyEvent.clear()
|
outgoingEvent(eventType).clear()
|
||||||
|
|
||||||
|
proc waitNotEmptyEvent[A, B](pool: PeerPool[A, B],
|
||||||
|
filter: set[PeerType]): Future[void] =
|
||||||
|
pool.waitForEvent(EventType.NotEmptyEvent, filter)
|
||||||
|
|
||||||
proc waitNotFullEvent[A, B](pool: PeerPool[A, B],
|
proc waitNotFullEvent[A, B](pool: PeerPool[A, B],
|
||||||
peerType: PeerType) {.async.} =
|
filter: set[PeerType]): Future[void] =
|
||||||
if peerType == PeerType.Incoming:
|
pool.waitForEvent(EventType.NotFullEvent, filter)
|
||||||
await pool.incNotFullEvent.wait()
|
|
||||||
pool.incNotFullEvent.clear()
|
|
||||||
elif peerType == PeerType.Outgoing:
|
|
||||||
await pool.outNotFullEvent.wait()
|
|
||||||
pool.outNotFullEvent.clear()
|
|
||||||
|
|
||||||
template getItem[A, B](pool: PeerPool[A, B],
|
template getItem[A, B](pool: PeerPool[A, B],
|
||||||
filter: set[PeerType]): ptr PeerItem[A] =
|
filter: set[PeerType]): ptr PeerItem[A] =
|
||||||
@ -336,20 +352,19 @@ proc addPeer*[A, B](pool: PeerPool[A, B],
|
|||||||
let peerKey = getKey(peer)
|
let peerKey = getKey(peer)
|
||||||
|
|
||||||
if not(pool.registry.hasKey(peerKey)) and not(peer.getFuture().finished):
|
if not(pool.registry.hasKey(peerKey)) and not(peer.getFuture().finished):
|
||||||
if len(pool.registry) >= pool.maxPeersCount:
|
while len(pool.registry) >= pool.maxPeersCount:
|
||||||
await pool.waitNotFullEvent(peerType)
|
await pool.waitNotFullEvent({PeerType.Incoming, PeerType.Outgoing})
|
||||||
if peerType == PeerType.Incoming:
|
if peerType == PeerType.Incoming:
|
||||||
if pool.curIncPeersCount >= pool.maxIncPeersCount:
|
while pool.curIncPeersCount >= pool.maxIncPeersCount:
|
||||||
await pool.waitNotFullEvent(peerType)
|
await pool.waitNotFullEvent({peerType})
|
||||||
let pindex = pool.addPeerImpl(peer, peerKey, peerType)
|
let pindex = pool.addPeerImpl(peer, peerKey, peerType)
|
||||||
inc(pool.curIncPeersCount)
|
inc(pool.curIncPeersCount)
|
||||||
pool.incQueue.push(pindex)
|
pool.incQueue.push(pindex)
|
||||||
pool.incNotEmptyEvent.fire()
|
pool.incNotEmptyEvent.fire()
|
||||||
res = true
|
res = true
|
||||||
elif peerType == PeerType.Outgoing:
|
elif peerType == PeerType.Outgoing:
|
||||||
if pool.curOutPeersCount >= pool.maxOutPeersCount:
|
while pool.curOutPeersCount >= pool.maxOutPeersCount:
|
||||||
await pool.waitNotFullEvent(peerType)
|
await pool.waitNotFullEvent({peerType})
|
||||||
|
|
||||||
let pindex = pool.addPeerImpl(peer, peerKey, peerType)
|
let pindex = pool.addPeerImpl(peer, peerKey, peerType)
|
||||||
inc(pool.curOutPeersCount)
|
inc(pool.curOutPeersCount)
|
||||||
pool.outQueue.push(pindex)
|
pool.outQueue.push(pindex)
|
||||||
|
@ -80,7 +80,7 @@ suiteReport "PeerPool testing suite":
|
|||||||
doAssert(fut1.finished == false)
|
doAssert(fut1.finished == false)
|
||||||
doAssert(fut2.finished == false)
|
doAssert(fut2.finished == false)
|
||||||
peer0.close()
|
peer0.close()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
doAssert(fut1.finished == false)
|
doAssert(fut1.finished == false)
|
||||||
doAssert(fut2.finished == true and fut2.failed == false)
|
doAssert(fut2.finished == true and fut2.failed == false)
|
||||||
result = true
|
result = true
|
||||||
@ -102,11 +102,11 @@ suiteReport "PeerPool testing suite":
|
|||||||
doAssert(fut2.finished == false)
|
doAssert(fut2.finished == false)
|
||||||
doAssert(fut3.finished == false)
|
doAssert(fut3.finished == false)
|
||||||
peer0.close()
|
peer0.close()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
doAssert(fut2.finished == true and fut2.failed == false)
|
doAssert(fut2.finished == true and fut2.failed == false)
|
||||||
doAssert(fut3.finished == false)
|
doAssert(fut3.finished == false)
|
||||||
peer1.close()
|
peer1.close()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
doAssert(fut3.finished == true and fut3.failed == false)
|
doAssert(fut3.finished == true and fut3.failed == false)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
@ -128,18 +128,61 @@ suiteReport "PeerPool testing suite":
|
|||||||
doAssert(fut2.finished == true and fut2.failed == false)
|
doAssert(fut2.finished == true and fut2.failed == false)
|
||||||
doAssert(fut3.finished == false)
|
doAssert(fut3.finished == false)
|
||||||
peer0.close()
|
peer0.close()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
doAssert(fut1.finished == true and fut1.failed == false)
|
doAssert(fut1.finished == true and fut1.failed == false)
|
||||||
doAssert(fut3.finished == false)
|
doAssert(fut3.finished == false)
|
||||||
peer2.close()
|
peer2.close()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
doAssert(fut3.finished == true and fut3.failed == false)
|
doAssert(fut3.finished == true and fut3.failed == false)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
proc testAddPeer4(): Future[bool] {.async.} =
|
||||||
|
var pool = newPeerPool[PeerTest, PeerTestID](maxPeers = 3)
|
||||||
|
|
||||||
|
var peer0 = PeerTest.init("idInc0")
|
||||||
|
var peer1 = PeerTest.init("idInc1")
|
||||||
|
var peer2 = PeerTest.init("idOut0")
|
||||||
|
var peer3 = PeerTest.init("idOut1")
|
||||||
|
var peer4 = PeerTest.init("idOut2")
|
||||||
|
var peer5 = PeerTest.init("idInc2")
|
||||||
|
|
||||||
|
var fut0 = pool.addIncomingPeer(peer0)
|
||||||
|
var fut1 = pool.addIncomingPeer(peer1)
|
||||||
|
var fut2 = pool.addOutgoingPeer(peer2)
|
||||||
|
var fut3 = pool.addOutgoingPeer(peer3)
|
||||||
|
var fut4 = pool.addOutgoingPeer(peer4)
|
||||||
|
var fut5 = pool.addIncomingPeer(peer5)
|
||||||
|
|
||||||
|
doAssert(fut0.finished == true and fut0.failed == false)
|
||||||
|
doAssert(fut1.finished == true and fut1.failed == false)
|
||||||
|
doAssert(fut2.finished == true and fut2.failed == false)
|
||||||
|
doAssert(fut3.finished == false)
|
||||||
|
doAssert(fut4.finished == false)
|
||||||
|
doAssert(fut5.finished == false)
|
||||||
|
|
||||||
|
await sleepAsync(10.milliseconds)
|
||||||
|
doAssert(fut3.finished == false)
|
||||||
|
doAssert(fut4.finished == false)
|
||||||
|
doAssert(fut5.finished == false)
|
||||||
|
peer0.close()
|
||||||
|
await sleepAsync(10.milliseconds)
|
||||||
|
doAssert(fut3.finished == true and fut3.failed == false)
|
||||||
|
doAssert(fut4.finished == false)
|
||||||
|
doAssert(fut5.finished == false)
|
||||||
|
peer1.close()
|
||||||
|
await sleepAsync(10.milliseconds)
|
||||||
|
doAssert(fut4.finished == true and fut4.failed == false)
|
||||||
|
doAssert(fut5.finished == false)
|
||||||
|
peer2.close()
|
||||||
|
await sleepAsync(10.milliseconds)
|
||||||
|
doAssert(fut5.finished == true and fut5.failed == false)
|
||||||
|
result = true
|
||||||
|
|
||||||
check:
|
check:
|
||||||
waitFor(testAddPeer1()) == true
|
waitFor(testAddPeer1()) == true
|
||||||
waitFor(testAddPeer2()) == true
|
waitFor(testAddPeer2()) == true
|
||||||
waitFor(testAddPeer3()) == true
|
waitFor(testAddPeer3()) == true
|
||||||
|
waitFor(testAddPeer4()) == true
|
||||||
|
|
||||||
timedTest "Acquire from empty pool":
|
timedTest "Acquire from empty pool":
|
||||||
var pool0 = newPeerPool[PeerTest, PeerTestID]()
|
var pool0 = newPeerPool[PeerTest, PeerTestID]()
|
||||||
@ -399,7 +442,7 @@ suiteReport "PeerPool testing suite":
|
|||||||
|
|
||||||
proc testConsumer() {.async.} =
|
proc testConsumer() {.async.} =
|
||||||
var p = await pool.acquire()
|
var p = await pool.acquire()
|
||||||
await sleepAsync(100.milliseconds)
|
await sleepAsync(10.milliseconds)
|
||||||
pool.release(p)
|
pool.release(p)
|
||||||
|
|
||||||
proc testClose(): Future[bool] {.async.} =
|
proc testClose(): Future[bool] {.async.} =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user