Skip to content

Commit c131e81

Browse files
authored
eth/fetcher, trie: unit test reliability fixes (#23020)
Some tests take quite some time during exit, which I think causes some appveyor fails like this: https://ci.appveyor.com/project/ethereum/go-ethereum/builds/39511210/job/xhom84eg2e4uulq3 One of the things that seem to take time during exit is waiting (up to 100ms) for the syncbloom to close. This PR changes it to use a channel, instead of looping with a 100ms wait. This also includes some unrelated changes improving the reliability of eth/fetcher tests, which fail a lot because they are time-dependent.
1 parent 686b288 commit c131e81

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

eth/fetcher/block_fetcher.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -833,15 +833,17 @@ func (f *BlockFetcher) importBlocks(peer string, block *types.Block) {
833833
// internal state.
834834
func (f *BlockFetcher) forgetHash(hash common.Hash) {
835835
// Remove all pending announces and decrement DOS counters
836-
for _, announce := range f.announced[hash] {
837-
f.announces[announce.origin]--
838-
if f.announces[announce.origin] <= 0 {
839-
delete(f.announces, announce.origin)
836+
if announceMap, ok := f.announced[hash]; ok {
837+
for _, announce := range announceMap {
838+
f.announces[announce.origin]--
839+
if f.announces[announce.origin] <= 0 {
840+
delete(f.announces, announce.origin)
841+
}
842+
}
843+
delete(f.announced, hash)
844+
if f.announceChangeHook != nil {
845+
f.announceChangeHook(hash, false)
840846
}
841-
}
842-
delete(f.announced, hash)
843-
if f.announceChangeHook != nil {
844-
f.announceChangeHook(hash, false)
845847
}
846848
// Remove any pending fetches and decrement the DOS counters
847849
if announce := f.fetching[hash]; announce != nil {

eth/fetcher/block_fetcher_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ func testInvalidNumberAnnouncement(t *testing.T, light bool) {
698698
badBodyFetcher := tester.makeBodyFetcher("bad", blocks, 0)
699699

700700
imported := make(chan interface{})
701+
announced := make(chan interface{})
701702
tester.fetcher.importedHook = func(header *types.Header, block *types.Block) {
702703
if light {
703704
if header == nil {
@@ -712,21 +713,35 @@ func testInvalidNumberAnnouncement(t *testing.T, light bool) {
712713
}
713714
}
714715
// Announce a block with a bad number, check for immediate drop
716+
tester.fetcher.announceChangeHook = func(hash common.Hash, b bool) {
717+
announced <- nil
718+
}
715719
tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher)
720+
verifyAnnounce := func() {
721+
for i := 0; i < 2; i++ {
722+
select {
723+
case <-announced:
724+
continue
725+
case <-time.After(1 * time.Second):
726+
t.Fatal("announce timeout")
727+
return
728+
}
729+
}
730+
}
731+
verifyAnnounce()
716732
verifyImportEvent(t, imported, false)
717-
718733
tester.lock.RLock()
719734
dropped := tester.drops["bad"]
720735
tester.lock.RUnlock()
721736

722737
if !dropped {
723738
t.Fatalf("peer with invalid numbered announcement not dropped")
724739
}
725-
726740
goodHeaderFetcher := tester.makeHeaderFetcher("good", blocks, -gatherSlack)
727741
goodBodyFetcher := tester.makeBodyFetcher("good", blocks, 0)
728742
// Make sure a good announcement passes without a drop
729743
tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher)
744+
verifyAnnounce()
730745
verifyImportEvent(t, imported, true)
731746

732747
tester.lock.RLock()

trie/sync_bloom.go

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ var (
4545
// provided disk database on creation in a background thread and will only start
4646
// returning live results once that's finished.
4747
type SyncBloom struct {
48-
bloom *bloomfilter.Filter
49-
inited uint32
50-
closer sync.Once
51-
closed uint32
52-
pend sync.WaitGroup
48+
bloom *bloomfilter.Filter
49+
inited uint32
50+
closer sync.Once
51+
closed uint32
52+
pend sync.WaitGroup
53+
closeCh chan struct{}
5354
}
5455

5556
// NewSyncBloom creates a new bloom filter of the given size (in megabytes) and
@@ -64,7 +65,8 @@ func NewSyncBloom(memory uint64, database ethdb.Iteratee) *SyncBloom {
6465

6566
// Assemble the fast sync bloom and init it from previous sessions
6667
b := &SyncBloom{
67-
bloom: bloom,
68+
bloom: bloom,
69+
closeCh: make(chan struct{}),
6870
}
6971
b.pend.Add(2)
7072
go func() {
@@ -125,16 +127,15 @@ func (b *SyncBloom) init(database ethdb.Iteratee) {
125127
// meter periodically recalculates the false positive error rate of the bloom
126128
// filter and reports it in a metric.
127129
func (b *SyncBloom) meter() {
130+
// check every second
131+
tick := time.NewTicker(1 * time.Second)
128132
for {
129-
// Report the current error ration. No floats, lame, scale it up.
130-
bloomErrorGauge.Update(int64(b.bloom.FalsePosititveProbability() * 100000))
131-
132-
// Wait one second, but check termination more frequently
133-
for i := 0; i < 10; i++ {
134-
if atomic.LoadUint32(&b.closed) == 1 {
135-
return
136-
}
137-
time.Sleep(100 * time.Millisecond)
133+
select {
134+
case <-tick.C:
135+
// Report the current error ration. No floats, lame, scale it up.
136+
bloomErrorGauge.Update(int64(b.bloom.FalsePosititveProbability() * 100000))
137+
case <-b.closeCh:
138+
return
138139
}
139140
}
140141
}
@@ -145,6 +146,7 @@ func (b *SyncBloom) Close() error {
145146
b.closer.Do(func() {
146147
// Ensure the initializer is stopped
147148
atomic.StoreUint32(&b.closed, 1)
149+
close(b.closeCh)
148150
b.pend.Wait()
149151

150152
// Wipe the bloom, but mark it "uninited" just in case someone attempts an access

0 commit comments

Comments
 (0)