diff options
author | Felix Lange <fjl@twurst.com> | 2016-03-29 09:08:16 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2016-05-09 19:03:08 +0800 |
commit | 56ed6152a11592d20220daf6322e94a009e6236d (patch) | |
tree | 0a0d5985832e32fdd1d9c3dc1deff89a85811099 /eth/peer.go | |
parent | f821b0188a27bca08cada87c5b746ef9455a2e96 (diff) | |
download | dexon-56ed6152a11592d20220daf6322e94a009e6236d.tar.gz dexon-56ed6152a11592d20220daf6322e94a009e6236d.tar.zst dexon-56ed6152a11592d20220daf6322e94a009e6236d.zip |
core, eth, miner: improve shutdown synchronisation
Shutting down geth prints hundreds of annoying error messages in some
cases. The errors appear because the Stop method of eth.ProtocolManager,
miner.Miner and core.TxPool is asynchronous. Left over peer sessions
generate events which are processed after Stop even though the database
has already been closed.
The fix is to make Stop synchronous using sync.WaitGroup.
For eth.ProtocolManager, in order to make use of WaitGroup safe, we need
a way to stop new peer sessions from being added while waiting on the
WaitGroup. The eth protocol Run function now selects on a signaling
channel and adds to the WaitGroup only if ProtocolManager is not
shutting down.
For miner.worker and core.TxPool the number of goroutines is static,
WaitGroup can be used in the usual way without additional
synchronisation.
Diffstat (limited to 'eth/peer.go')
-rw-r--r-- | eth/peer.go | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/eth/peer.go b/eth/peer.go index 15ba22ff5..8eb41b0f9 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -34,6 +34,7 @@ import ( ) var ( + errClosed = errors.New("peer set is closed") errAlreadyRegistered = errors.New("peer is already registered") errNotRegistered = errors.New("peer is not registered") ) @@ -351,8 +352,9 @@ func (p *peer) String() string { // peerSet represents the collection of active peers currently participating in // the Ethereum sub-protocol. type peerSet struct { - peers map[string]*peer - lock sync.RWMutex + peers map[string]*peer + lock sync.RWMutex + closed bool } // newPeerSet creates a new peer set to track the active participants. @@ -368,6 +370,9 @@ func (ps *peerSet) Register(p *peer) error { ps.lock.Lock() defer ps.lock.Unlock() + if ps.closed { + return errClosed + } if _, ok := ps.peers[p.id]; ok { return errAlreadyRegistered } @@ -450,3 +455,15 @@ func (ps *peerSet) BestPeer() *peer { } return bestPeer } + +// Close disconnects all peers. +// No new peers can be registered after Close has returned. +func (ps *peerSet) Close() { + ps.lock.Lock() + defer ps.lock.Unlock() + + for _, p := range ps.peers { + p.Disconnect(p2p.DiscQuitting) + } + ps.closed = true +} |