github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/block_cache.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "sync" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/core/types" 24 ) 25 26 // BlockCache implements a caching mechanism specifically for blocks and uses FILO to pop 27 type BlockCache struct { 28 size int 29 30 hashes []common.Hash 31 blocks map[common.Hash]*types.Block 32 33 mu sync.RWMutex 34 } 35 36 // Creates and returns a `BlockCache` with `size`. If `size` is smaller than 1 it will panic 37 func NewBlockCache(size int) *BlockCache { 38 if size < 1 { 39 panic("block cache size not allowed to be smaller than 1") 40 } 41 42 bc := &BlockCache{size: size} 43 bc.Clear() 44 return bc 45 } 46 47 func (bc *BlockCache) Clear() { 48 bc.blocks = make(map[common.Hash]*types.Block) 49 bc.hashes = nil 50 51 } 52 53 func (bc *BlockCache) Push(block *types.Block) { 54 bc.mu.Lock() 55 defer bc.mu.Unlock() 56 57 if len(bc.hashes) == bc.size { 58 delete(bc.blocks, bc.hashes[0]) 59 60 // XXX There are a few other options on solving this 61 // 1) use a poller / GC like mechanism to clean up untracked objects 62 // 2) copy as below 63 // re-use the slice and remove the reference to bc.hashes[0] 64 // this will allow the element to be garbage collected. 65 copy(bc.hashes, bc.hashes[1:]) 66 } else { 67 bc.hashes = append(bc.hashes, common.Hash{}) 68 } 69 70 hash := block.Hash() 71 bc.blocks[hash] = block 72 bc.hashes[len(bc.hashes)-1] = hash 73 } 74 75 func (bc *BlockCache) Delete(hash common.Hash) { 76 bc.mu.Lock() 77 defer bc.mu.Unlock() 78 79 if _, ok := bc.blocks[hash]; ok { 80 delete(bc.blocks, hash) 81 for i, h := range bc.hashes { 82 if hash == h { 83 bc.hashes = bc.hashes[:i+copy(bc.hashes[i:], bc.hashes[i+1:])] 84 // or ? => bc.hashes = append(bc.hashes[:i], bc.hashes[i+1]...) 85 86 break 87 } 88 } 89 } 90 } 91 92 func (bc *BlockCache) Get(hash common.Hash) *types.Block { 93 bc.mu.RLock() 94 defer bc.mu.RUnlock() 95 96 if block, haz := bc.blocks[hash]; haz { 97 return block 98 } 99 100 return nil 101 } 102 103 func (bc *BlockCache) Has(hash common.Hash) bool { 104 bc.mu.RLock() 105 defer bc.mu.RUnlock() 106 107 _, ok := bc.blocks[hash] 108 return ok 109 } 110 111 func (bc *BlockCache) Each(cb func(int, *types.Block)) { 112 bc.mu.Lock() 113 defer bc.mu.Unlock() 114 115 i := 0 116 for _, block := range bc.blocks { 117 cb(i, block) 118 i++ 119 } 120 }