Skip to content

Commit cf7c44a

Browse files
committed
eth/downloader: detailed comment for the race corner case
1 parent 9c03c37 commit cf7c44a

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

eth/downloader/downloader.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,7 @@ out:
522522
peer.Promote()
523523
peer.SetIdle()
524524
glog.V(logger.Detail).Infof("%s: delivered %d blocks", peer, len(blockPack.blocks))
525-
if atomic.LoadInt32(&d.processing) == 0 {
526-
go d.process()
527-
}
525+
go d.process()
528526

529527
case errInvalidChain:
530528
// The hash chain is invalid (blocks are not ordered properly), abort
@@ -701,6 +699,19 @@ func (d *Downloader) banBlocks(peerId string, head common.Hash) error {
701699
}
702700

703701
// process takes blocks from the queue and tries to import them into the chain.
702+
//
703+
// The algorithmic flow is as follows:
704+
// - The `processing` flag is swapped to 1 to ensure singleton access
705+
// - The current `cancel` channel is retrieved to detect sync abortions
706+
// - Blocks are iteratively taken from the cache and inserted into the chain
707+
// - When the cache becomes empty, insertion stops
708+
// - The `processing` flag is swapped back to 0
709+
// - A post-exit check is made whether new blocks became available
710+
// - This step is important: it handles a potential race condition between
711+
// checking for no more work, and releasing the processing "mutex". In
712+
// between these state changes, a block may have arrived, but a processing
713+
// attempt denied, so we need to re-enter to ensure the block isn't left
714+
// to idle in the cache.
704715
func (d *Downloader) process() (err error) {
705716
// Make sure only one goroutine is ever allowed to process blocks at once
706717
if !atomic.CompareAndSwapInt32(&d.processing, 0, 1) {
@@ -763,7 +774,7 @@ func (d *Downloader) process() (err error) {
763774
// Try to inset the blocks, drop the originating peer if there's an error
764775
index, err := d.insertChain(raw)
765776
if err != nil {
766-
glog.V(logger.Debug).Infoln("Block #%d import failed:", raw[index].NumberU64(), err)
777+
glog.V(logger.Debug).Infof("Block #%d import failed: %v", raw[index].NumberU64(), err)
767778
d.dropPeer(blocks[index].OriginPeer)
768779
d.Cancel()
769780
return errCancelChainImport

0 commit comments

Comments
 (0)