| 
									
										
										
										
											2015-03-20 15:54:42 +01:00
										 |  |  | 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 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-23 12:12:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (bc *BlockCache) Has(hash common.Hash) bool { | 
					
						
							|  |  |  | 	_, ok := bc.blocks[hash] | 
					
						
							|  |  |  | 	return ok | 
					
						
							|  |  |  | } |