| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- // Copyright 2017 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package downloader
- import (
- "sync"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/log"
- )
- // syncState starts downloading state with the given root hash.
- func (d *Downloader) syncState(root common.Hash) *stateSync {
- // Create the state sync
- s := newStateSync(d, root)
- select {
- case d.stateSyncStart <- s:
- // If we tell the statesync to restart with a new root, we also need
- // to wait for it to actually also start -- when old requests have timed
- // out or been delivered
- <-s.started
- case <-d.quitCh:
- s.err = errCancelStateFetch
- close(s.done)
- }
- return s
- }
- // stateFetcher manages the active state sync and accepts requests
- // on its behalf.
- func (d *Downloader) stateFetcher() {
- for {
- select {
- case s := <-d.stateSyncStart:
- for next := s; next != nil; {
- next = d.runStateSync(next)
- }
- case <-d.quitCh:
- return
- }
- }
- }
- // runStateSync runs a state synchronisation until it completes or another root
- // hash is requested to be switched over to.
- func (d *Downloader) runStateSync(s *stateSync) *stateSync {
- log.Trace("State sync starting", "root", s.root)
- go s.run()
- defer s.Cancel()
- for {
- select {
- case next := <-d.stateSyncStart:
- return next
- case <-s.done:
- return nil
- }
- }
- }
- // stateSync schedules requests for downloading a particular state trie defined
- // by a given state root.
- type stateSync struct {
- d *Downloader // Downloader instance to access and manage current peerset
- root common.Hash // State root currently being synced
- started chan struct{} // Started is signalled once the sync loop starts
- cancel chan struct{} // Channel to signal a termination request
- cancelOnce sync.Once // Ensures cancel only ever gets called once
- done chan struct{} // Channel to signal termination completion
- err error // Any error hit during sync (set before completion)
- }
- // newStateSync creates a new state trie download scheduler. This method does not
- // yet start the sync. The user needs to call run to initiate.
- func newStateSync(d *Downloader, root common.Hash) *stateSync {
- return &stateSync{
- d: d,
- root: root,
- cancel: make(chan struct{}),
- done: make(chan struct{}),
- started: make(chan struct{}),
- }
- }
- // run starts the task assignment and response processing loop, blocking until
- // it finishes, and finally notifying any goroutines waiting for the loop to
- // finish.
- func (s *stateSync) run() {
- close(s.started)
- s.err = s.d.SnapSyncer.Sync(s.root, s.cancel)
- close(s.done)
- }
- // Wait blocks until the sync is done or canceled.
- func (s *stateSync) Wait() error {
- <-s.done
- return s.err
- }
- // Cancel cancels the sync and waits until it has shut down.
- func (s *stateSync) Cancel() error {
- s.cancelOnce.Do(func() {
- close(s.cancel)
- })
- return s.Wait()
- }
|