github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/state_synchronization/requester/jobs/execution_data_reader.go (about) 1 package jobs 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/onflow/flow-go/model/flow" 9 "github.com/onflow/flow-go/module" 10 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 11 "github.com/onflow/flow-go/module/executiondatasync/execution_data/cache" 12 "github.com/onflow/flow-go/module/irrecoverable" 13 "github.com/onflow/flow-go/storage" 14 ) 15 16 // BlockEntry represents a block that's tracked by the ExecutionDataRequester 17 type BlockEntry struct { 18 BlockID flow.Identifier 19 Height uint64 20 ExecutionData *execution_data.BlockExecutionDataEntity 21 } 22 23 var _ module.Jobs = (*ExecutionDataReader)(nil) 24 25 // ExecutionDataReader provides an abstraction for consumers to read blocks as job. 26 type ExecutionDataReader struct { 27 store *cache.ExecutionDataCache 28 29 fetchTimeout time.Duration 30 highestConsecutiveHeight func() (uint64, error) 31 32 // TODO: refactor this to accept a context in AtIndex instead of storing it on the struct. 33 // This requires also refactoring jobqueue.Consumer 34 ctx irrecoverable.SignalerContext 35 } 36 37 // NewExecutionDataReader creates and returns a ExecutionDataReader. 38 func NewExecutionDataReader( 39 store *cache.ExecutionDataCache, 40 fetchTimeout time.Duration, 41 highestConsecutiveHeight func() (uint64, error), 42 ) *ExecutionDataReader { 43 return &ExecutionDataReader{ 44 store: store, 45 fetchTimeout: fetchTimeout, 46 highestConsecutiveHeight: highestConsecutiveHeight, 47 } 48 } 49 50 // AddContext adds a context to the execution data reader 51 // TODO: this is an anti-pattern, refactor this to accept a context in AtIndex instead of storing 52 // it on the struct. 53 func (r *ExecutionDataReader) AddContext(ctx irrecoverable.SignalerContext) { 54 r.ctx = ctx 55 } 56 57 // AtIndex returns the block entry job at the given height, or storage.ErrNotFound. 58 // Any other error is unexpected 59 func (r *ExecutionDataReader) AtIndex(height uint64) (module.Job, error) { 60 if r.ctx == nil { 61 return nil, fmt.Errorf("execution data reader is not initialized") 62 } 63 64 // data for the requested height or a lower height, has not been downloaded yet. 65 highestHeight, err := r.highestConsecutiveHeight() 66 if err != nil { 67 return nil, fmt.Errorf("failed to get highest height: %w", err) 68 } 69 70 if height > highestHeight { 71 return nil, storage.ErrNotFound 72 } 73 74 ctx, cancel := context.WithTimeout(r.ctx, r.fetchTimeout) 75 defer cancel() 76 77 executionData, err := r.store.ByHeight(ctx, height) 78 if err != nil { 79 return nil, fmt.Errorf("failed to get execution data for height %d: %w", height, err) 80 } 81 82 return BlockEntryToJob(&BlockEntry{ 83 BlockID: executionData.BlockID, 84 Height: height, 85 ExecutionData: executionData, 86 }), nil 87 } 88 89 // Head returns the highest consecutive block height with downloaded execution data 90 func (r *ExecutionDataReader) Head() (uint64, error) { 91 return r.highestConsecutiveHeight() 92 }