mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
p2p/discover: decouple nodeFeed from Table mutex in waitForNodes
This commit is contained in:
parent
11cb8b55a6
commit
85e81382ad
1 changed files with 39 additions and 12 deletions
|
|
@ -753,6 +753,36 @@ func (tab *Table) deleteNode(n *enode.Node) {
|
|||
|
||||
// waitForNodes blocks until the table contains at least n nodes.
|
||||
func (tab *Table) waitForNodes(ctx context.Context, n int) error {
|
||||
// Set up a notification channel that gets unblocked when there was any activity on
|
||||
// the table. Ultimately this reads from the table's nodeFeed, but can't use the feed
|
||||
// directly on the same goroutine that takes Table.mutex, it would deadlock.
|
||||
var notify chan struct{}
|
||||
var notifyErr error
|
||||
initsub := func() event.Subscription {
|
||||
notify = make(chan struct{}, 1)
|
||||
newnode := make(chan *enode.Node, 1)
|
||||
sub := tab.nodeFeed.Subscribe(newnode)
|
||||
go func() {
|
||||
defer close(notify)
|
||||
for {
|
||||
select {
|
||||
case <-newnode:
|
||||
select {
|
||||
case notify <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
case <-ctx.Done():
|
||||
notifyErr = ctx.Err()
|
||||
return
|
||||
case <-tab.closeReq:
|
||||
notifyErr = errClosed
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sub
|
||||
}
|
||||
|
||||
getlength := func() (count int) {
|
||||
for _, b := range &tab.buckets {
|
||||
count += len(b.entries)
|
||||
|
|
@ -760,28 +790,25 @@ func (tab *Table) waitForNodes(ctx context.Context, n int) error {
|
|||
return count
|
||||
}
|
||||
|
||||
var ch chan *enode.Node
|
||||
for {
|
||||
tab.mutex.Lock()
|
||||
if getlength() >= n {
|
||||
tab.mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
if ch == nil {
|
||||
// Init subscription.
|
||||
ch = make(chan *enode.Node)
|
||||
sub := tab.nodeFeed.Subscribe(ch)
|
||||
if notify == nil {
|
||||
// Lazily init the subscription.
|
||||
sub := initsub()
|
||||
defer sub.Unsubscribe()
|
||||
}
|
||||
tab.mutex.Unlock()
|
||||
|
||||
// Wait for a node add event.
|
||||
select {
|
||||
case <-ch:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-tab.closeReq:
|
||||
return errClosed
|
||||
// Wait for table event.
|
||||
_, ok := <-notify
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
return notifyErr
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue