|
|
@ -17,6 +17,8 @@ |
|
|
|
package main |
|
|
|
package main |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
|
|
|
|
"sync" |
|
|
|
|
|
|
|
"sync/atomic" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/log" |
|
|
|
"github.com/ethereum/go-ethereum/log" |
|
|
@ -34,6 +36,7 @@ type crawler struct { |
|
|
|
|
|
|
|
|
|
|
|
// settings
|
|
|
|
// settings
|
|
|
|
revalidateInterval time.Duration |
|
|
|
revalidateInterval time.Duration |
|
|
|
|
|
|
|
mu sync.RWMutex |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
const ( |
|
|
@ -67,7 +70,7 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler |
|
|
|
return c |
|
|
|
return c |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *crawler) run(timeout time.Duration) nodeSet { |
|
|
|
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
timeoutTimer = time.NewTimer(timeout) |
|
|
|
timeoutTimer = time.NewTimer(timeout) |
|
|
|
timeoutCh <-chan time.Time |
|
|
|
timeoutCh <-chan time.Time |
|
|
@ -75,35 +78,51 @@ func (c *crawler) run(timeout time.Duration) nodeSet { |
|
|
|
doneCh = make(chan enode.Iterator, len(c.iters)) |
|
|
|
doneCh = make(chan enode.Iterator, len(c.iters)) |
|
|
|
liveIters = len(c.iters) |
|
|
|
liveIters = len(c.iters) |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
if nthreads < 1 { |
|
|
|
|
|
|
|
nthreads = 1 |
|
|
|
|
|
|
|
} |
|
|
|
defer timeoutTimer.Stop() |
|
|
|
defer timeoutTimer.Stop() |
|
|
|
defer statusTicker.Stop() |
|
|
|
defer statusTicker.Stop() |
|
|
|
for _, it := range c.iters { |
|
|
|
for _, it := range c.iters { |
|
|
|
go c.runIterator(doneCh, it) |
|
|
|
go c.runIterator(doneCh, it) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
added int |
|
|
|
added uint64 |
|
|
|
updated int |
|
|
|
updated uint64 |
|
|
|
skipped int |
|
|
|
skipped uint64 |
|
|
|
recent int |
|
|
|
recent uint64 |
|
|
|
removed int |
|
|
|
removed uint64 |
|
|
|
|
|
|
|
wg sync.WaitGroup |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
wg.Add(nthreads) |
|
|
|
|
|
|
|
for i := 0; i < nthreads; i++ { |
|
|
|
|
|
|
|
go func() { |
|
|
|
|
|
|
|
defer wg.Done() |
|
|
|
|
|
|
|
for { |
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case n := <-c.ch: |
|
|
|
|
|
|
|
switch c.updateNode(n) { |
|
|
|
|
|
|
|
case nodeSkipIncompat: |
|
|
|
|
|
|
|
atomic.AddUint64(&skipped, 1) |
|
|
|
|
|
|
|
case nodeSkipRecent: |
|
|
|
|
|
|
|
atomic.AddUint64(&recent, 1) |
|
|
|
|
|
|
|
case nodeRemoved: |
|
|
|
|
|
|
|
atomic.AddUint64(&removed, 1) |
|
|
|
|
|
|
|
case nodeAdded: |
|
|
|
|
|
|
|
atomic.AddUint64(&added, 1) |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
atomic.AddUint64(&updated, 1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case <-c.closed: |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
loop: |
|
|
|
loop: |
|
|
|
for { |
|
|
|
for { |
|
|
|
select { |
|
|
|
select { |
|
|
|
case n := <-c.ch: |
|
|
|
|
|
|
|
switch c.updateNode(n) { |
|
|
|
|
|
|
|
case nodeSkipIncompat: |
|
|
|
|
|
|
|
skipped++ |
|
|
|
|
|
|
|
case nodeSkipRecent: |
|
|
|
|
|
|
|
recent++ |
|
|
|
|
|
|
|
case nodeRemoved: |
|
|
|
|
|
|
|
removed++ |
|
|
|
|
|
|
|
case nodeAdded: |
|
|
|
|
|
|
|
added++ |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
updated++ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case it := <-doneCh: |
|
|
|
case it := <-doneCh: |
|
|
|
if it == c.inputIter { |
|
|
|
if it == c.inputIter { |
|
|
|
// Enable timeout when we're done revalidating the input nodes.
|
|
|
|
// Enable timeout when we're done revalidating the input nodes.
|
|
|
@ -119,8 +138,11 @@ loop: |
|
|
|
break loop |
|
|
|
break loop |
|
|
|
case <-statusTicker.C: |
|
|
|
case <-statusTicker.C: |
|
|
|
log.Info("Crawling in progress", |
|
|
|
log.Info("Crawling in progress", |
|
|
|
"added", added, "updated", updated, "removed", removed, |
|
|
|
"added", atomic.LoadUint64(&added), |
|
|
|
"ignored(recent)", recent, "ignored(incompatible)", skipped) |
|
|
|
"updated", atomic.LoadUint64(&updated), |
|
|
|
|
|
|
|
"removed", atomic.LoadUint64(&removed), |
|
|
|
|
|
|
|
"ignored(recent)", atomic.LoadUint64(&removed), |
|
|
|
|
|
|
|
"ignored(incompatible)", atomic.LoadUint64(&skipped)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -131,6 +153,7 @@ loop: |
|
|
|
for ; liveIters > 0; liveIters-- { |
|
|
|
for ; liveIters > 0; liveIters-- { |
|
|
|
<-doneCh |
|
|
|
<-doneCh |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
wg.Wait() |
|
|
|
return c.output |
|
|
|
return c.output |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -148,7 +171,9 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) { |
|
|
|
// updateNode updates the info about the given node, and returns a status
|
|
|
|
// updateNode updates the info about the given node, and returns a status
|
|
|
|
// about what changed
|
|
|
|
// about what changed
|
|
|
|
func (c *crawler) updateNode(n *enode.Node) int { |
|
|
|
func (c *crawler) updateNode(n *enode.Node) int { |
|
|
|
|
|
|
|
c.mu.RLock() |
|
|
|
node, ok := c.output[n.ID()] |
|
|
|
node, ok := c.output[n.ID()] |
|
|
|
|
|
|
|
c.mu.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
// Skip validation of recently-seen nodes.
|
|
|
|
// Skip validation of recently-seen nodes.
|
|
|
|
if ok && time.Since(node.LastCheck) < c.revalidateInterval { |
|
|
|
if ok && time.Since(node.LastCheck) < c.revalidateInterval { |
|
|
@ -156,10 +181,9 @@ func (c *crawler) updateNode(n *enode.Node) int { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Request the node record.
|
|
|
|
// Request the node record.
|
|
|
|
nn, err := c.disc.RequestENR(n) |
|
|
|
|
|
|
|
node.LastCheck = truncNow() |
|
|
|
|
|
|
|
status := nodeUpdated |
|
|
|
status := nodeUpdated |
|
|
|
if err != nil { |
|
|
|
node.LastCheck = truncNow() |
|
|
|
|
|
|
|
if nn, err := c.disc.RequestENR(n); err != nil { |
|
|
|
if node.Score == 0 { |
|
|
|
if node.Score == 0 { |
|
|
|
// Node doesn't implement EIP-868.
|
|
|
|
// Node doesn't implement EIP-868.
|
|
|
|
log.Debug("Skipping node", "id", n.ID()) |
|
|
|
log.Debug("Skipping node", "id", n.ID()) |
|
|
@ -176,8 +200,9 @@ func (c *crawler) updateNode(n *enode.Node) int { |
|
|
|
} |
|
|
|
} |
|
|
|
node.LastResponse = node.LastCheck |
|
|
|
node.LastResponse = node.LastCheck |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Store/update node in output set.
|
|
|
|
// Store/update node in output set.
|
|
|
|
|
|
|
|
c.mu.Lock() |
|
|
|
|
|
|
|
defer c.mu.Unlock() |
|
|
|
if node.Score <= 0 { |
|
|
|
if node.Score <= 0 { |
|
|
|
log.Debug("Removing node", "id", n.ID()) |
|
|
|
log.Debug("Removing node", "id", n.ID()) |
|
|
|
delete(c.output, n.ID()) |
|
|
|
delete(c.output, n.ID()) |
|
|
|