69 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			69 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | package core | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"sync" | ||
|  | 
 | ||
|  | 	"github.com/ethereum/go-ethereum/common" | ||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||
|  | ) | ||
|  | 
 | ||
|  | // BlockCache implements a caching mechanism specifically for blocks and uses FILO to pop | ||
|  | type BlockCache struct { | ||
|  | 	size int | ||
|  | 
 | ||
|  | 	hashes []common.Hash | ||
|  | 	blocks map[common.Hash]*types.Block | ||
|  | 
 | ||
|  | 	mu sync.RWMutex | ||
|  | } | ||
|  | 
 | ||
|  | // Creates and returns a `BlockCache` with `size`. If `size` is smaller than 1 it will panic | ||
|  | func NewBlockCache(size int) *BlockCache { | ||
|  | 	if size < 1 { | ||
|  | 		panic("block cache size not allowed to be smaller than 1") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	bc := &BlockCache{size: size} | ||
|  | 	bc.Clear() | ||
|  | 	return bc | ||
|  | } | ||
|  | 
 | ||
|  | func (bc *BlockCache) Clear() { | ||
|  | 	bc.blocks = make(map[common.Hash]*types.Block) | ||
|  | 	bc.hashes = nil | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | func (bc *BlockCache) Push(block *types.Block) { | ||
|  | 	bc.mu.Lock() | ||
|  | 	defer bc.mu.Unlock() | ||
|  | 
 | ||
|  | 	if len(bc.hashes) == bc.size { | ||
|  | 		delete(bc.blocks, bc.hashes[0]) | ||
|  | 
 | ||
|  | 		// XXX There are a few other options on solving this | ||
|  | 		// 1) use a poller / GC like mechanism to clean up untracked objects | ||
|  | 		// 2) copy as below | ||
|  | 		// re-use the slice and remove the reference to bc.hashes[0] | ||
|  | 		// this will allow the element to be garbage collected. | ||
|  | 		copy(bc.hashes, bc.hashes[1:]) | ||
|  | 	} else { | ||
|  | 		bc.hashes = append(bc.hashes, common.Hash{}) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	hash := block.Hash() | ||
|  | 	bc.blocks[hash] = block | ||
|  | 	bc.hashes[len(bc.hashes)-1] = hash | ||
|  | } | ||
|  | 
 | ||
|  | func (bc *BlockCache) Get(hash common.Hash) *types.Block { | ||
|  | 	bc.mu.RLock() | ||
|  | 	defer bc.mu.RUnlock() | ||
|  | 
 | ||
|  | 	if block, haz := bc.blocks[hash]; haz { | ||
|  | 		return block | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return nil | ||
|  | } |