Compare commits
3 Commits
fde127e9b9
...
e15cb3e553
Author | SHA1 | Date |
---|---|---|
Arran Schlosberg | e15cb3e553 | |
Arran Schlosberg | 5b4ac11371 | |
Arran Schlosberg | 2e75e74435 |
|
@ -18,6 +18,8 @@ package state
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -66,6 +68,57 @@ func TestUseAfterTerminate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSchdeulerTerminationRaceCondition(t *testing.T) {
|
||||
// The lock-based implementation of [subfetcher] had a race condition
|
||||
// whereby schedule() could obtain the lock after the <-sf.stop branch of
|
||||
// loop() had already checked for an empty queue. Although probabilistic,
|
||||
// this test reliably triggered at a rates of (~4 in 10k) and (~100 in 50k)
|
||||
// on an Apple M3 Max chip.
|
||||
|
||||
t.Parallel()
|
||||
db := filledStateDB()
|
||||
skey := common.HexToHash("aaa")
|
||||
|
||||
// Maximise concurrency by synchronising all scheduling and termination.
|
||||
start := make(chan struct{})
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
raceInduced atomic.Uint64
|
||||
)
|
||||
|
||||
const numTrials = 50_000
|
||||
for i := 0; i < numTrials; i++ {
|
||||
wg.Add(2)
|
||||
fetcher := newSubfetcher(db.db, db.originalRoot, common.Hash{}, db.originalRoot, common.Address{})
|
||||
|
||||
var gotScheduleErr error
|
||||
doneScheduling := make(chan struct{})
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
gotScheduleErr = fetcher.schedule(nil, []common.Hash{skey}, false)
|
||||
close(doneScheduling)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
fetcher.terminate(false /*async*/)
|
||||
|
||||
<-doneScheduling
|
||||
if gotScheduleErr == nil && len(fetcher.tasks) > 0 {
|
||||
raceInduced.Add(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
close(start)
|
||||
wg.Wait()
|
||||
if got := raceInduced.Load(); got > 0 {
|
||||
t.Errorf("In %d/%d concurrent trials %T.schedule() returned nil error but >0 tasks remain in queue after %[3]T.terminate([blocking]) returned", got, numTrials, &subfetcher{})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerklePrefetcher(t *testing.T) {
|
||||
disk := rawdb.NewMemoryDatabase()
|
||||
db := triedb.NewDatabase(disk, triedb.VerkleDefaults)
|
||||
|
|
Loading…
Reference in New Issue