1717package main
1818
1919import (
20+ "sync"
21+ "sync/atomic"
2022 "time"
2123
2224 "github.com/ethereum/go-ethereum/log"
@@ -34,6 +36,7 @@ type crawler struct {
3436
3537 // settings
3638 revalidateInterval time.Duration
39+ mu sync.RWMutex
3740}
3841
3942const (
@@ -67,43 +70,59 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler
6770 return c
6871}
6972
70- func (c * crawler ) run (timeout time.Duration ) nodeSet {
73+ func (c * crawler ) run (timeout time.Duration , nthreads int ) nodeSet {
7174 var (
7275 timeoutTimer = time .NewTimer (timeout )
7376 timeoutCh <- chan time.Time
7477 statusTicker = time .NewTicker (time .Second * 8 )
7578 doneCh = make (chan enode.Iterator , len (c .iters ))
7679 liveIters = len (c .iters )
7780 )
81+ if nthreads < 1 {
82+ nthreads = 1
83+ }
7884 defer timeoutTimer .Stop ()
7985 defer statusTicker .Stop ()
8086 for _ , it := range c .iters {
8187 go c .runIterator (doneCh , it )
8288 }
83-
8489 var (
85- added int
86- updated int
87- skipped int
88- recent int
89- removed int
90+ added uint64
91+ updated uint64
92+ skipped uint64
93+ recent uint64
94+ removed uint64
95+ wg sync.WaitGroup
9096 )
97+ wg .Add (nthreads )
98+ for i := 0 ; i < nthreads ; i ++ {
99+ go func () {
100+ defer wg .Done ()
101+ for {
102+ select {
103+ case n := <- c .ch :
104+ switch c .updateNode (n ) {
105+ case nodeSkipIncompat :
106+ atomic .AddUint64 (& skipped , 1 )
107+ case nodeSkipRecent :
108+ atomic .AddUint64 (& recent , 1 )
109+ case nodeRemoved :
110+ atomic .AddUint64 (& removed , 1 )
111+ case nodeAdded :
112+ atomic .AddUint64 (& added , 1 )
113+ default :
114+ atomic .AddUint64 (& updated , 1 )
115+ }
116+ case <- c .closed :
117+ return
118+ }
119+ }
120+ }()
121+ }
122+
91123loop:
92124 for {
93125 select {
94- case n := <- c .ch :
95- switch c .updateNode (n ) {
96- case nodeSkipIncompat :
97- skipped ++
98- case nodeSkipRecent :
99- recent ++
100- case nodeRemoved :
101- removed ++
102- case nodeAdded :
103- added ++
104- default :
105- updated ++
106- }
107126 case it := <- doneCh :
108127 if it == c .inputIter {
109128 // Enable timeout when we're done revalidating the input nodes.
@@ -119,8 +138,11 @@ loop:
119138 break loop
120139 case <- statusTicker .C :
121140 log .Info ("Crawling in progress" ,
122- "added" , added , "updated" , updated , "removed" , removed ,
123- "ignored(recent)" , recent , "ignored(incompatible)" , skipped )
141+ "added" , atomic .LoadUint64 (& added ),
142+ "updated" , atomic .LoadUint64 (& updated ),
143+ "removed" , atomic .LoadUint64 (& removed ),
144+ "ignored(recent)" , atomic .LoadUint64 (& removed ),
145+ "ignored(incompatible)" , atomic .LoadUint64 (& skipped ))
124146 }
125147 }
126148
@@ -131,6 +153,7 @@ loop:
131153 for ; liveIters > 0 ; liveIters -- {
132154 <- doneCh
133155 }
156+ wg .Wait ()
134157 return c .output
135158}
136159
@@ -148,18 +171,19 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) {
148171// updateNode updates the info about the given node, and returns a status
149172// about what changed
150173func (c * crawler ) updateNode (n * enode.Node ) int {
174+ c .mu .RLock ()
151175 node , ok := c .output [n .ID ()]
176+ c .mu .RUnlock ()
152177
153178 // Skip validation of recently-seen nodes.
154179 if ok && time .Since (node .LastCheck ) < c .revalidateInterval {
155180 return nodeSkipRecent
156181 }
157182
158183 // Request the node record.
159- nn , err := c .disc .RequestENR (n )
160- node .LastCheck = truncNow ()
161184 status := nodeUpdated
162- if err != nil {
185+ node .LastCheck = truncNow ()
186+ if nn , err := c .disc .RequestENR (n ); err != nil {
163187 if node .Score == 0 {
164188 // Node doesn't implement EIP-868.
165189 log .Debug ("Skipping node" , "id" , n .ID ())
@@ -176,8 +200,9 @@ func (c *crawler) updateNode(n *enode.Node) int {
176200 }
177201 node .LastResponse = node .LastCheck
178202 }
179-
180203 // Store/update node in output set.
204+ c .mu .Lock ()
205+ defer c .mu .Unlock ()
181206 if node .Score <= 0 {
182207 log .Debug ("Removing node" , "id" , n .ID ())
183208 delete (c .output , n .ID ())
0 commit comments