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  }