mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
les: handle conn/disc/reg logic in the eventloop
This commit is contained in:
parent
8c4a7fa8d3
commit
b434d767e2
1 changed files with 135 additions and 58 deletions
|
|
@ -87,6 +87,26 @@ const (
|
||||||
initStatsWeight = 1
|
initStatsWeight = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// connReq represents a request for peer connection.
|
||||||
|
type connReq struct {
|
||||||
|
p *peer
|
||||||
|
ip net.IP
|
||||||
|
port uint16
|
||||||
|
cont chan *poolEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// discReq represents a request for peer disconnection.
|
||||||
|
type discReq struct {
|
||||||
|
entry *poolEntry
|
||||||
|
cont chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerReq represents a request for peer registration.
|
||||||
|
type registerReq struct {
|
||||||
|
entry *poolEntry
|
||||||
|
cont chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
// serverPool implements a pool for storing and selecting newly discovered and already
|
// serverPool implements a pool for storing and selecting newly discovered and already
|
||||||
// known light server nodes. It received discovered nodes, stores statistics about
|
// known light server nodes. It received discovered nodes, stores statistics about
|
||||||
// known nodes and takes care of always having enough good quality servers connected.
|
// known nodes and takes care of always having enough good quality servers connected.
|
||||||
|
|
@ -109,6 +129,10 @@ type serverPool struct {
|
||||||
timeout, enableRetry chan *poolEntry
|
timeout, enableRetry chan *poolEntry
|
||||||
adjustStats chan poolStatAdjust
|
adjustStats chan poolStatAdjust
|
||||||
|
|
||||||
|
connCh chan *connReq
|
||||||
|
discCh chan *discReq
|
||||||
|
registerCh chan *registerReq
|
||||||
|
|
||||||
knownQueue, newQueue poolEntryQueue
|
knownQueue, newQueue poolEntryQueue
|
||||||
knownSelect, newSelect *weightedRandomSelect
|
knownSelect, newSelect *weightedRandomSelect
|
||||||
knownSelected, newSelected int
|
knownSelected, newSelected int
|
||||||
|
|
@ -125,6 +149,9 @@ func newServerPool(db ethdb.Database, quit chan struct{}, wg *sync.WaitGroup) *s
|
||||||
timeout: make(chan *poolEntry, 1),
|
timeout: make(chan *poolEntry, 1),
|
||||||
adjustStats: make(chan poolStatAdjust, 100),
|
adjustStats: make(chan poolStatAdjust, 100),
|
||||||
enableRetry: make(chan *poolEntry, 1),
|
enableRetry: make(chan *poolEntry, 1),
|
||||||
|
connCh: make(chan *connReq),
|
||||||
|
discCh: make(chan *discReq),
|
||||||
|
registerCh: make(chan *registerReq),
|
||||||
knownSelect: newWeightedRandomSelect(),
|
knownSelect: newWeightedRandomSelect(),
|
||||||
newSelect: newWeightedRandomSelect(),
|
newSelect: newWeightedRandomSelect(),
|
||||||
fastDiscover: true,
|
fastDiscover: true,
|
||||||
|
|
@ -158,46 +185,27 @@ func (pool *serverPool) start(server *p2p.Server, topic discv5.Topic) {
|
||||||
// Note that whenever a connection has been accepted and a pool entry has been returned,
|
// Note that whenever a connection has been accepted and a pool entry has been returned,
|
||||||
// disconnect should also always be called.
|
// disconnect should also always be called.
|
||||||
func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry {
|
func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry {
|
||||||
pool.lock.Lock()
|
log.Debug("Connect new entry", "enode", p.id)
|
||||||
defer pool.lock.Unlock()
|
req := &connReq{p: p, ip: ip, port: port, cont: make(chan *poolEntry, 1)}
|
||||||
entry := pool.entries[p.ID()]
|
select {
|
||||||
if entry == nil {
|
case pool.connCh <- req:
|
||||||
entry = pool.findOrNewNode(p.ID(), ip, port)
|
case <-pool.quit:
|
||||||
}
|
|
||||||
p.Log().Debug("Connecting to new peer", "state", entry.state)
|
|
||||||
if entry.state == psConnected || entry.state == psRegistered {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pool.connWg.Add(1)
|
return <-req.cont
|
||||||
entry.peer = p
|
|
||||||
entry.state = psConnected
|
|
||||||
addr := &poolEntryAddress{
|
|
||||||
ip: ip,
|
|
||||||
port: port,
|
|
||||||
lastSeen: mclock.Now(),
|
|
||||||
}
|
|
||||||
entry.lastConnected = addr
|
|
||||||
entry.addr = make(map[string]*poolEntryAddress)
|
|
||||||
entry.addr[addr.strKey()] = addr
|
|
||||||
entry.addrSelect = *newWeightedRandomSelect()
|
|
||||||
entry.addrSelect.update(addr)
|
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// registered should be called after a successful handshake
|
// registered should be called after a successful handshake
|
||||||
func (pool *serverPool) registered(entry *poolEntry) {
|
func (pool *serverPool) registered(entry *poolEntry) {
|
||||||
log.Debug("Registered new entry", "enode", entry.id)
|
log.Debug("Registered new entry", "enode", entry.id)
|
||||||
pool.lock.Lock()
|
req := ®isterReq{entry: entry, cont: make(chan struct{})}
|
||||||
defer pool.lock.Unlock()
|
select {
|
||||||
|
case pool.registerCh <- req:
|
||||||
entry.state = psRegistered
|
case <-pool.quit:
|
||||||
entry.regTime = mclock.Now()
|
return
|
||||||
if !entry.known {
|
|
||||||
pool.newQueue.remove(entry)
|
|
||||||
entry.known = true
|
|
||||||
}
|
}
|
||||||
pool.knownQueue.setLatest(entry)
|
<-req.cont
|
||||||
entry.shortRetry = shortRetryCnt
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnect should be called when ending a connection. Service quality statistics
|
// disconnect should be called when ending a connection. Service quality statistics
|
||||||
|
|
@ -205,36 +213,45 @@ func (pool *serverPool) registered(entry *poolEntry) {
|
||||||
// only connection statistics are updated, just like in case of timeout)
|
// only connection statistics are updated, just like in case of timeout)
|
||||||
func (pool *serverPool) disconnect(entry *poolEntry) {
|
func (pool *serverPool) disconnect(entry *poolEntry) {
|
||||||
log.Debug("Disconnected old entry", "enode", entry.id)
|
log.Debug("Disconnected old entry", "enode", entry.id)
|
||||||
pool.lock.Lock()
|
stopped := false
|
||||||
defer pool.lock.Unlock()
|
select {
|
||||||
|
case <-pool.quit:
|
||||||
|
stopped = true
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
if entry.state == psRegistered {
|
if stopped {
|
||||||
connTime := mclock.Now() - entry.regTime
|
// Request is emitted by ourselves, handle the logic here since eventloop doesn't
|
||||||
connAdjust := float64(connTime) / float64(targetConnTime)
|
// serve requests anymore.
|
||||||
if connAdjust > 1 {
|
pool.lock.Lock()
|
||||||
connAdjust = 1
|
defer pool.lock.Unlock()
|
||||||
}
|
|
||||||
stopped := false
|
if entry.state == psRegistered {
|
||||||
select {
|
connTime := mclock.Now() - entry.regTime
|
||||||
case <-pool.quit:
|
connAdjust := float64(connTime) / float64(targetConnTime)
|
||||||
stopped = true
|
if connAdjust > 1 {
|
||||||
default:
|
connAdjust = 1
|
||||||
}
|
}
|
||||||
if stopped {
|
|
||||||
entry.connectStats.add(1, connAdjust)
|
entry.connectStats.add(1, connAdjust)
|
||||||
} else {
|
|
||||||
entry.connectStats.add(connAdjust, 1)
|
|
||||||
}
|
}
|
||||||
}
|
entry.state = psNotConnected
|
||||||
|
if entry.knownSelected {
|
||||||
entry.state = psNotConnected
|
pool.knownSelected--
|
||||||
if entry.knownSelected {
|
} else {
|
||||||
pool.knownSelected--
|
pool.newSelected--
|
||||||
|
}
|
||||||
|
pool.setRetryDial(entry)
|
||||||
|
pool.connWg.Done()
|
||||||
} else {
|
} else {
|
||||||
pool.newSelected--
|
// Request is emitted by the server side
|
||||||
|
req := &discReq{entry: entry, cont: make(chan struct{})}
|
||||||
|
select {
|
||||||
|
case pool.discCh <- req:
|
||||||
|
case <-pool.quit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
<-req.cont
|
||||||
}
|
}
|
||||||
pool.setRetryDial(entry)
|
|
||||||
pool.connWg.Done()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -327,6 +344,67 @@ func (pool *serverPool) eventLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case req := <-pool.connCh:
|
||||||
|
// Handle peer connection requests.
|
||||||
|
entry := pool.entries[req.p.ID()]
|
||||||
|
if entry == nil {
|
||||||
|
entry = pool.findOrNewNode(req.p.ID(), req.ip, req.port)
|
||||||
|
}
|
||||||
|
req.p.Log().Debug("Connecting to new peer", "state", entry.state)
|
||||||
|
if entry.state == psConnected || entry.state == psRegistered {
|
||||||
|
req.cont <- nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pool.connWg.Add(1)
|
||||||
|
entry.peer = req.p
|
||||||
|
entry.state = psConnected
|
||||||
|
addr := &poolEntryAddress{
|
||||||
|
ip: req.ip,
|
||||||
|
port: req.port,
|
||||||
|
lastSeen: mclock.Now(),
|
||||||
|
}
|
||||||
|
entry.lastConnected = addr
|
||||||
|
entry.addr = make(map[string]*poolEntryAddress)
|
||||||
|
entry.addr[addr.strKey()] = addr
|
||||||
|
entry.addrSelect = *newWeightedRandomSelect()
|
||||||
|
entry.addrSelect.update(addr)
|
||||||
|
req.cont <- entry
|
||||||
|
|
||||||
|
case req := <-pool.registerCh:
|
||||||
|
// Handle peer registration requests.
|
||||||
|
entry := req.entry
|
||||||
|
entry.state = psRegistered
|
||||||
|
entry.regTime = mclock.Now()
|
||||||
|
if !entry.known {
|
||||||
|
pool.newQueue.remove(entry)
|
||||||
|
entry.known = true
|
||||||
|
}
|
||||||
|
pool.knownQueue.setLatest(entry)
|
||||||
|
entry.shortRetry = shortRetryCnt
|
||||||
|
close(req.cont)
|
||||||
|
|
||||||
|
case req := <-pool.discCh:
|
||||||
|
// Handle peer disconnection requests.
|
||||||
|
entry := req.entry
|
||||||
|
if entry.state == psRegistered {
|
||||||
|
connTime := mclock.Now() - entry.regTime
|
||||||
|
connAdjust := float64(connTime) / float64(targetConnTime)
|
||||||
|
if connAdjust > 1 {
|
||||||
|
connAdjust = 1
|
||||||
|
}
|
||||||
|
entry.connectStats.add(connAdjust, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.state = psNotConnected
|
||||||
|
if entry.knownSelected {
|
||||||
|
pool.knownSelected--
|
||||||
|
} else {
|
||||||
|
pool.newSelected--
|
||||||
|
}
|
||||||
|
pool.setRetryDial(entry)
|
||||||
|
pool.connWg.Done()
|
||||||
|
close(req.cont)
|
||||||
|
|
||||||
case <-pool.quit:
|
case <-pool.quit:
|
||||||
if pool.discSetPeriod != nil {
|
if pool.discSetPeriod != nil {
|
||||||
close(pool.discSetPeriod)
|
close(pool.discSetPeriod)
|
||||||
|
|
@ -335,7 +413,6 @@ func (pool *serverPool) eventLoop() {
|
||||||
pool.saveNodes()
|
pool.saveNodes()
|
||||||
pool.wg.Done()
|
pool.wg.Done()
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue