mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
test: demonstrate fix of race condition in locking impl
This commit is contained in:
parent
fde127e9b9
commit
2e75e74435
1 changed files with 50 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -66,6 +67,55 @@ 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 rate of ~4 in 10,000 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
|
||||||
|
|
||||||
|
for i := 0; i < 50_000; i++ {
|
||||||
|
wg.Add(3)
|
||||||
|
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)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
<-doneScheduling
|
||||||
|
fetcher.wait()
|
||||||
|
|
||||||
|
if gotScheduleErr == nil && len(fetcher.tasks) > 0 {
|
||||||
|
t.Errorf("%T.schedule() returned nil error but %d task(s) remain in queue after %T.wait() returned", fetcher, len(fetcher.tasks), fetcher)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
close(start)
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
func TestVerklePrefetcher(t *testing.T) {
|
func TestVerklePrefetcher(t *testing.T) {
|
||||||
disk := rawdb.NewMemoryDatabase()
|
disk := rawdb.NewMemoryDatabase()
|
||||||
db := triedb.NewDatabase(disk, triedb.VerkleDefaults)
|
db := triedb.NewDatabase(disk, triedb.VerkleDefaults)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue