github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/state_synchronization/indexer/collection_executed_metric.go (about) 1 package indexer 2 3 import ( 4 "errors" 5 "time" 6 7 "github.com/rs/zerolog" 8 9 "github.com/onflow/flow-go/model/flow" 10 "github.com/onflow/flow-go/module" 11 "github.com/onflow/flow-go/module/mempool/stdmap" 12 "github.com/onflow/flow-go/storage" 13 ) 14 15 var _ module.CollectionExecutedMetric = (*CollectionExecutedMetricImpl)(nil) 16 17 // CollectionExecutedMetricImpl tracks metrics to measure how long it takes for tx to reach each step in their lifecycle 18 type CollectionExecutedMetricImpl struct { 19 log zerolog.Logger // used to log relevant actions with context 20 21 accessMetrics module.AccessMetrics 22 collectionsToMarkFinalized *stdmap.Times 23 collectionsToMarkExecuted *stdmap.Times 24 blocksToMarkExecuted *stdmap.Times 25 26 collections storage.Collections 27 blocks storage.Blocks 28 } 29 30 func NewCollectionExecutedMetricImpl( 31 log zerolog.Logger, 32 accessMetrics module.AccessMetrics, 33 collectionsToMarkFinalized *stdmap.Times, 34 collectionsToMarkExecuted *stdmap.Times, 35 blocksToMarkExecuted *stdmap.Times, 36 collections storage.Collections, 37 blocks storage.Blocks, 38 ) (*CollectionExecutedMetricImpl, error) { 39 return &CollectionExecutedMetricImpl{ 40 log: log, 41 accessMetrics: accessMetrics, 42 collectionsToMarkFinalized: collectionsToMarkFinalized, 43 collectionsToMarkExecuted: collectionsToMarkExecuted, 44 blocksToMarkExecuted: blocksToMarkExecuted, 45 collections: collections, 46 blocks: blocks, 47 }, nil 48 } 49 50 // CollectionFinalized tracks collections to mark finalized 51 func (c *CollectionExecutedMetricImpl) CollectionFinalized(light flow.LightCollection) { 52 if ti, found := c.collectionsToMarkFinalized.ByID(light.ID()); found { 53 for _, t := range light.Transactions { 54 c.accessMetrics.TransactionFinalized(t, ti) 55 } 56 c.collectionsToMarkFinalized.Remove(light.ID()) 57 } 58 } 59 60 // CollectionExecuted tracks collections to mark executed 61 func (c *CollectionExecutedMetricImpl) CollectionExecuted(light flow.LightCollection) { 62 if ti, found := c.collectionsToMarkExecuted.ByID(light.ID()); found { 63 for _, t := range light.Transactions { 64 c.accessMetrics.TransactionExecuted(t, ti) 65 } 66 c.collectionsToMarkExecuted.Remove(light.ID()) 67 } 68 } 69 70 // BlockFinalized tracks finalized metric for block 71 func (c *CollectionExecutedMetricImpl) BlockFinalized(block *flow.Block) { 72 // TODO: lookup actual finalization time by looking at the block finalizing `b` 73 now := time.Now().UTC() 74 blockID := block.ID() 75 76 // mark all transactions as finalized 77 // TODO: sample to reduce performance overhead 78 for _, g := range block.Payload.Guarantees { 79 l, err := c.collections.LightByID(g.CollectionID) 80 if errors.Is(err, storage.ErrNotFound) { 81 c.collectionsToMarkFinalized.Add(g.CollectionID, now) 82 continue 83 } else if err != nil { 84 c.log.Warn().Err(err).Str("collection_id", g.CollectionID.String()). 85 Msg("could not track tx finalized metric: finalized collection not found locally") 86 continue 87 } 88 89 for _, t := range l.Transactions { 90 c.accessMetrics.TransactionFinalized(t, now) 91 } 92 } 93 94 if ti, found := c.blocksToMarkExecuted.ByID(blockID); found { 95 c.blockExecuted(block, ti) 96 c.accessMetrics.UpdateExecutionReceiptMaxHeight(block.Header.Height) 97 c.blocksToMarkExecuted.Remove(blockID) 98 } 99 } 100 101 // ExecutionReceiptReceived tracks execution receipt metrics 102 func (c *CollectionExecutedMetricImpl) ExecutionReceiptReceived(r *flow.ExecutionReceipt) { 103 // TODO add actual execution time to execution receipt? 104 now := time.Now().UTC() 105 106 // retrieve the block 107 // TODO: consider using storage.Index.ByBlockID, the index contains collection id and seals ID 108 b, err := c.blocks.ByID(r.ExecutionResult.BlockID) 109 110 if errors.Is(err, storage.ErrNotFound) { 111 c.blocksToMarkExecuted.Add(r.ExecutionResult.BlockID, now) 112 return 113 } 114 115 if err != nil { 116 c.log.Warn().Err(err).Msg("could not track tx executed metric: executed block not found locally") 117 return 118 } 119 120 c.accessMetrics.UpdateExecutionReceiptMaxHeight(b.Header.Height) 121 122 c.blockExecuted(b, now) 123 } 124 125 func (c *CollectionExecutedMetricImpl) UpdateLastFullBlockHeight(height uint64) { 126 c.accessMetrics.UpdateLastFullBlockHeight(height) 127 } 128 129 // blockExecuted tracks executed metric for block 130 func (c *CollectionExecutedMetricImpl) blockExecuted(block *flow.Block, ti time.Time) { 131 // mark all transactions as executed 132 // TODO: sample to reduce performance overhead 133 for _, g := range block.Payload.Guarantees { 134 l, err := c.collections.LightByID(g.CollectionID) 135 if errors.Is(err, storage.ErrNotFound) { 136 c.collectionsToMarkExecuted.Add(g.CollectionID, ti) 137 continue 138 } else if err != nil { 139 c.log.Warn().Err(err).Str("collection_id", g.CollectionID.String()). 140 Msg("could not track tx executed metric: executed collection not found locally") 141 continue 142 } 143 144 for _, t := range l.Transactions { 145 c.accessMetrics.TransactionExecuted(t, ti) 146 } 147 } 148 }