github.com/decred/dcrlnd@v0.7.6/blockcache/blockcache.go (about) 1 package blockcache 2 3 import ( 4 "context" 5 6 "github.com/decred/dcrd/chaincfg/chainhash" 7 "github.com/decred/dcrd/dcrutil/v4" 8 "github.com/decred/dcrd/wire" 9 "github.com/decred/dcrlnd/lntypes" 10 "github.com/decred/dcrlnd/multimutex" 11 cache "github.com/decred/dcrlnd/neutrinocache" 12 "github.com/decred/dcrlnd/neutrinocache/lru" 13 ) 14 15 // BlockCache is an lru cache for blocks. 16 type BlockCache struct { 17 Cache *lru.Cache 18 HashMutex *multimutex.HashMutex 19 } 20 21 // NewBlockCache creates a new BlockCache with the given maximum capacity. 22 func NewBlockCache(capacity uint64) *BlockCache { 23 return &BlockCache{ 24 Cache: lru.NewCache(capacity), 25 HashMutex: multimutex.NewHashMutex(), 26 } 27 } 28 29 // GetBlock first checks to see if the BlockCache already contains the block 30 // with the given hash. If it does then the block is fetched from the cache and 31 // returned. Otherwise the getBlockImpl function is used in order to fetch the 32 // new block and then it is stored in the block cache and returned. 33 func (bc *BlockCache) GetBlock(ctx context.Context, hash *chainhash.Hash, 34 getBlockImpl func(ctx context.Context, hash *chainhash.Hash) (*wire.MsgBlock, 35 error)) (*wire.MsgBlock, error) { 36 37 // A nil BlockCache performs no caching. 38 if bc == nil { 39 return getBlockImpl(ctx, hash) 40 } 41 42 bc.HashMutex.Lock(lntypes.Hash(*hash)) 43 defer bc.HashMutex.Unlock(lntypes.Hash(*hash)) 44 45 // Create an inv vector for getting the block. 46 inv := wire.NewInvVect(wire.InvTypeBlock, hash) 47 48 // Check if the block corresponding to the given hash is already 49 // stored in the blockCache and return it if it is. 50 cacheBlock, err := bc.Cache.Get(*inv) 51 if err != nil && err != cache.ErrElementNotFound { 52 return nil, err 53 } 54 if cacheBlock != nil { 55 return cacheBlock.(*cache.CacheableBlock).MsgBlock(), nil 56 } 57 58 // Fetch the block from the chain backends. 59 block, err := getBlockImpl(ctx, hash) 60 if err != nil { 61 return nil, err 62 } 63 64 // Add the new block to blockCache. If the Cache is at its maximum 65 // capacity then the LFU item will be evicted in favour of this new 66 // block. 67 _, err = bc.Cache.Put( 68 *inv, &cache.CacheableBlock{ 69 Block: dcrutil.NewBlock(block), 70 }, 71 ) 72 if err != nil { 73 return nil, err 74 } 75 76 return block, nil 77 }