Allow parallel state processor to be interrupted by caller

This commit is contained in:
Jerry 2023-04-14 10:29:59 -07:00
parent d76fc157aa
commit 48c1f9078d
3 changed files with 22 additions and 14 deletions

View file

@ -2,6 +2,7 @@ package blockstm
import ( import (
"container/heap" "container/heap"
"context"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -369,13 +370,14 @@ func (pe *ParallelExecutor) Prepare() {
}(i) }(i)
} }
pe.settleWg.Add(len(pe.tasks)) pe.settleWg.Add(1)
go func() { go func() {
for t := range pe.chSettle { for t := range pe.chSettle {
pe.tasks[t].Settle() pe.tasks[t].Settle()
pe.settleWg.Done()
} }
pe.settleWg.Done()
}() }()
// bootstrap first execution // bootstrap first execution
@ -390,18 +392,15 @@ func (pe *ParallelExecutor) Prepare() {
func (pe *ParallelExecutor) Close(wait bool) { func (pe *ParallelExecutor) Close(wait bool) {
close(pe.chTasks) close(pe.chTasks)
close(pe.chSpeculativeTasks) close(pe.chSpeculativeTasks)
close(pe.chSettle)
if wait { if wait {
pe.workerWg.Wait() pe.workerWg.Wait()
} }
close(pe.chResults)
if wait { if wait {
pe.settleWg.Wait() pe.settleWg.Wait()
} }
close(pe.chSettle)
} }
// nolint: gocognit // nolint: gocognit
@ -412,7 +411,7 @@ func (pe *ParallelExecutor) Step(res *ExecResult) (result ParallelExecutionResul
// If the transaction failed when we know it should not fail, this means the transaction itself is // If the transaction failed when we know it should not fail, this means the transaction itself is
// bad (e.g. wrong nonce), and we should exit the execution immediately // bad (e.g. wrong nonce), and we should exit the execution immediately
err = fmt.Errorf("could not apply tx %d [%v]: %w", tx, pe.tasks[tx].Hash(), abortErr.OriginError) err = fmt.Errorf("could not apply tx %d [%v]: %w", tx, pe.tasks[tx].Hash(), abortErr.OriginError)
pe.Close(false) pe.Close(true)
return return
} }
@ -582,7 +581,7 @@ func (pe *ParallelExecutor) Step(res *ExecResult) (result ParallelExecutionResul
type PropertyCheck func(*ParallelExecutor) error type PropertyCheck func(*ParallelExecutor) error
func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyCheck, metadata bool) (result ParallelExecutionResult, err error) { func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyCheck, metadata bool, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
if len(tasks) == 0 { if len(tasks) == 0 {
return ParallelExecutionResult{MakeTxnInputOutput(len(tasks)), nil, nil, nil}, nil return ParallelExecutionResult{MakeTxnInputOutput(len(tasks)), nil, nil, nil}, nil
} }
@ -591,6 +590,15 @@ func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyChec
pe.Prepare() pe.Prepare()
for range pe.chResults { for range pe.chResults {
if interruptCtx != nil {
select {
case <-interruptCtx.Done():
pe.Close(true)
return result, interruptCtx.Err()
default:
}
}
res := pe.resultQueue.Pop().(ExecResult) res := pe.resultQueue.Pop().(ExecResult)
result, err = pe.Step(&res) result, err = pe.Step(&res)
@ -611,6 +619,6 @@ func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyChec
return return
} }
func ExecuteParallel(tasks []ExecTask, profile bool, metadata bool) (result ParallelExecutionResult, err error) { func ExecuteParallel(tasks []ExecTask, profile bool, metadata bool, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
return executeParallelWithCheck(tasks, profile, nil, metadata) return executeParallelWithCheck(tasks, profile, nil, metadata, interruptCtx)
} }

View file

@ -424,7 +424,7 @@ func runParallel(t *testing.T, tasks []ExecTask, validation PropertyCheck, metad
profile := false profile := false
start := time.Now() start := time.Now()
result, err := executeParallelWithCheck(tasks, false, validation, metadata) result, err := executeParallelWithCheck(tasks, false, validation, metadata, nil)
if result.Deps != nil && profile { if result.Deps != nil && profile {
result.Deps.Report(*result.Stats, func(str string) { fmt.Println(str) }) result.Deps.Report(*result.Stats, func(str string) { fmt.Println(str) })
@ -458,7 +458,7 @@ func runParallelGetMetadata(t *testing.T, tasks []ExecTask, validation PropertyC
t.Helper() t.Helper()
// fmt.Println("len(tasks)", len(tasks)) // fmt.Println("len(tasks)", len(tasks))
res, err := executeParallelWithCheck(tasks, true, validation, false) res, err := executeParallelWithCheck(tasks, true, validation, false, nil)
assert.NoError(t, err, "error occur during parallel execution") assert.NoError(t, err, "error occur during parallel execution")

View file

@ -376,7 +376,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
backupStateDB := statedb.Copy() backupStateDB := statedb.Copy()
profile := false profile := false
result, err := blockstm.ExecuteParallel(tasks, false, metadata) result, err := blockstm.ExecuteParallel(tasks, false, metadata, interruptCtx)
if err == nil && profile { if err == nil && profile {
_, weight := result.Deps.LongestPath(*result.Stats) _, weight := result.Deps.LongestPath(*result.Stats)
@ -412,7 +412,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
t.totalUsedGas = usedGas t.totalUsedGas = usedGas
} }
_, err = blockstm.ExecuteParallel(tasks, false, metadata) _, err = blockstm.ExecuteParallel(tasks, false, metadata, interruptCtx)
break break
} }