github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/badger/light_transaction_results.go (about) 1 package badger 2 3 import ( 4 "fmt" 5 6 "github.com/dgraph-io/badger/v2" 7 8 "github.com/onflow/flow-go/model/flow" 9 "github.com/onflow/flow-go/module" 10 "github.com/onflow/flow-go/module/metrics" 11 "github.com/onflow/flow-go/storage" 12 "github.com/onflow/flow-go/storage/badger/operation" 13 ) 14 15 var _ storage.LightTransactionResults = (*LightTransactionResults)(nil) 16 17 type LightTransactionResults struct { 18 db *badger.DB 19 cache *Cache[string, flow.LightTransactionResult] 20 indexCache *Cache[string, flow.LightTransactionResult] 21 blockCache *Cache[string, []flow.LightTransactionResult] 22 } 23 24 func NewLightTransactionResults(collector module.CacheMetrics, db *badger.DB, transactionResultsCacheSize uint) *LightTransactionResults { 25 retrieve := func(key string) func(tx *badger.Txn) (flow.LightTransactionResult, error) { 26 var txResult flow.LightTransactionResult 27 return func(tx *badger.Txn) (flow.LightTransactionResult, error) { 28 29 blockID, txID, err := KeyToBlockIDTransactionID(key) 30 if err != nil { 31 return flow.LightTransactionResult{}, fmt.Errorf("could not convert key: %w", err) 32 } 33 34 err = operation.RetrieveLightTransactionResult(blockID, txID, &txResult)(tx) 35 if err != nil { 36 return flow.LightTransactionResult{}, handleError(err, flow.LightTransactionResult{}) 37 } 38 return txResult, nil 39 } 40 } 41 retrieveIndex := func(key string) func(tx *badger.Txn) (flow.LightTransactionResult, error) { 42 var txResult flow.LightTransactionResult 43 return func(tx *badger.Txn) (flow.LightTransactionResult, error) { 44 45 blockID, txIndex, err := KeyToBlockIDIndex(key) 46 if err != nil { 47 return flow.LightTransactionResult{}, fmt.Errorf("could not convert index key: %w", err) 48 } 49 50 err = operation.RetrieveLightTransactionResultByIndex(blockID, txIndex, &txResult)(tx) 51 if err != nil { 52 return flow.LightTransactionResult{}, handleError(err, flow.LightTransactionResult{}) 53 } 54 return txResult, nil 55 } 56 } 57 retrieveForBlock := func(key string) func(tx *badger.Txn) ([]flow.LightTransactionResult, error) { 58 var txResults []flow.LightTransactionResult 59 return func(tx *badger.Txn) ([]flow.LightTransactionResult, error) { 60 61 blockID, err := KeyToBlockID(key) 62 if err != nil { 63 return nil, fmt.Errorf("could not convert index key: %w", err) 64 } 65 66 err = operation.LookupLightTransactionResultsByBlockIDUsingIndex(blockID, &txResults)(tx) 67 if err != nil { 68 return nil, handleError(err, flow.LightTransactionResult{}) 69 } 70 return txResults, nil 71 } 72 } 73 return &LightTransactionResults{ 74 db: db, 75 cache: newCache[string, flow.LightTransactionResult](collector, metrics.ResourceTransactionResults, 76 withLimit[string, flow.LightTransactionResult](transactionResultsCacheSize), 77 withStore(noopStore[string, flow.LightTransactionResult]), 78 withRetrieve(retrieve), 79 ), 80 indexCache: newCache[string, flow.LightTransactionResult](collector, metrics.ResourceTransactionResultIndices, 81 withLimit[string, flow.LightTransactionResult](transactionResultsCacheSize), 82 withStore(noopStore[string, flow.LightTransactionResult]), 83 withRetrieve(retrieveIndex), 84 ), 85 blockCache: newCache[string, []flow.LightTransactionResult](collector, metrics.ResourceTransactionResultIndices, 86 withLimit[string, []flow.LightTransactionResult](transactionResultsCacheSize), 87 withStore(noopStore[string, []flow.LightTransactionResult]), 88 withRetrieve(retrieveForBlock), 89 ), 90 } 91 } 92 93 func (tr *LightTransactionResults) BatchStore(blockID flow.Identifier, transactionResults []flow.LightTransactionResult, batch storage.BatchStorage) error { 94 writeBatch := batch.GetWriter() 95 96 for i, result := range transactionResults { 97 err := operation.BatchInsertLightTransactionResult(blockID, &result)(writeBatch) 98 if err != nil { 99 return fmt.Errorf("cannot batch insert tx result: %w", err) 100 } 101 102 err = operation.BatchIndexLightTransactionResult(blockID, uint32(i), &result)(writeBatch) 103 if err != nil { 104 return fmt.Errorf("cannot batch index tx result: %w", err) 105 } 106 } 107 108 batch.OnSucceed(func() { 109 for i, result := range transactionResults { 110 key := KeyFromBlockIDTransactionID(blockID, result.TransactionID) 111 // cache for each transaction, so that it's faster to retrieve 112 tr.cache.Insert(key, result) 113 114 index := uint32(i) 115 116 keyIndex := KeyFromBlockIDIndex(blockID, index) 117 tr.indexCache.Insert(keyIndex, result) 118 } 119 120 key := KeyFromBlockID(blockID) 121 tr.blockCache.Insert(key, transactionResults) 122 }) 123 return nil 124 } 125 126 // ByBlockIDTransactionID returns the transaction result for the given block ID and transaction ID 127 func (tr *LightTransactionResults) ByBlockIDTransactionID(blockID flow.Identifier, txID flow.Identifier) (*flow.LightTransactionResult, error) { 128 tx := tr.db.NewTransaction(false) 129 defer tx.Discard() 130 key := KeyFromBlockIDTransactionID(blockID, txID) 131 transactionResult, err := tr.cache.Get(key)(tx) 132 if err != nil { 133 return nil, err 134 } 135 return &transactionResult, nil 136 } 137 138 // ByBlockIDTransactionIndex returns the transaction result for the given blockID and transaction index 139 func (tr *LightTransactionResults) ByBlockIDTransactionIndex(blockID flow.Identifier, txIndex uint32) (*flow.LightTransactionResult, error) { 140 tx := tr.db.NewTransaction(false) 141 defer tx.Discard() 142 key := KeyFromBlockIDIndex(blockID, txIndex) 143 transactionResult, err := tr.indexCache.Get(key)(tx) 144 if err != nil { 145 return nil, err 146 } 147 return &transactionResult, nil 148 } 149 150 // ByBlockID gets all transaction results for a block, ordered by transaction index 151 func (tr *LightTransactionResults) ByBlockID(blockID flow.Identifier) ([]flow.LightTransactionResult, error) { 152 tx := tr.db.NewTransaction(false) 153 defer tx.Discard() 154 key := KeyFromBlockID(blockID) 155 transactionResults, err := tr.blockCache.Get(key)(tx) 156 if err != nil { 157 return nil, err 158 } 159 return transactionResults, nil 160 }