github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/storage/derived/derived_chain_data.go (about) 1 package derived 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/hashicorp/golang-lru/v2/simplelru" 8 9 "github.com/onflow/flow-go/model/flow" 10 ) 11 12 const DefaultDerivedDataCacheSize = 1000 13 14 // DerivedChainData is a cache of DerivedBlockData databases used for speeding up 15 // cadence execution. 16 // 17 // Since programs are derived from external source, the DerivedBlockData databases 18 // need not be durable and can be recreated on the fly. 19 type DerivedChainData struct { 20 // NOTE: It's unsafe to use RWMutex since lru updates the data structure 21 // on Get. 22 mutex sync.Mutex 23 24 lru *simplelru.LRU[flow.Identifier, *DerivedBlockData] 25 } 26 27 func NewDerivedChainData(chainCacheSize uint) (*DerivedChainData, error) { 28 lru, err := simplelru.NewLRU[flow.Identifier, *DerivedBlockData](int(chainCacheSize), nil) 29 if err != nil { 30 return nil, fmt.Errorf("cannot create LRU cache: %w", err) 31 } 32 33 return &DerivedChainData{ 34 lru: lru, 35 }, nil 36 } 37 38 func (chain *DerivedChainData) unsafeGet( 39 currentBlockId flow.Identifier, 40 ) *DerivedBlockData { 41 currentEntry, ok := chain.lru.Get(currentBlockId) 42 if ok { 43 return currentEntry 44 } 45 46 return nil 47 } 48 49 func (chain *DerivedChainData) Get( 50 currentBlockId flow.Identifier, 51 ) *DerivedBlockData { 52 chain.mutex.Lock() 53 defer chain.mutex.Unlock() 54 55 return chain.unsafeGet(currentBlockId) 56 } 57 58 func (chain *DerivedChainData) GetOrCreateDerivedBlockData( 59 currentBlockId flow.Identifier, 60 parentBlockId flow.Identifier, 61 ) *DerivedBlockData { 62 chain.mutex.Lock() 63 defer chain.mutex.Unlock() 64 65 currentEntry := chain.unsafeGet(currentBlockId) 66 if currentEntry != nil { 67 return currentEntry 68 } 69 70 var current *DerivedBlockData 71 parentEntry, ok := chain.lru.Get(parentBlockId) 72 if ok { 73 current = parentEntry.NewChildDerivedBlockData() 74 } else { 75 current = NewEmptyDerivedBlockData(0) 76 } 77 78 chain.lru.Add(currentBlockId, current) 79 return current 80 } 81 82 func (chain *DerivedChainData) NewDerivedBlockDataForScript( 83 currentBlockId flow.Identifier, 84 ) *DerivedBlockData { 85 block := chain.Get(currentBlockId) 86 if block != nil { 87 return block.NewChildDerivedBlockData() 88 } 89 90 return NewEmptyDerivedBlockData(0) 91 }