github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/database/cache.go (about) 1 package database 2 3 import ( 4 "encoding/hex" 5 "strconv" 6 7 "github.com/golang/groupcache/singleflight" 8 9 "github.com/bytom/bytom/common" 10 "github.com/bytom/bytom/protocol/bc" 11 "github.com/bytom/bytom/protocol/bc/types" 12 "github.com/bytom/bytom/protocol/state" 13 ) 14 15 const ( 16 maxCachedBlockHeaders = 2048 17 maxCachedBlockTransactions = 1024 18 maxCachedBlockHashes = 1024 19 maxCachedMainChainHashes = 1024 20 maxCheckPoints = 256 21 ) 22 23 type fillBlockHeaderFn func(hash *bc.Hash) (*types.BlockHeader, error) 24 type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error) 25 type fillBlockHashesFn func(height uint64) ([]*bc.Hash, error) 26 type fillMainChainHashFn func(height uint64) (*bc.Hash, error) 27 type fillCheckPointFn func(key []byte) (*state.Checkpoint, error) 28 29 func newCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillBlockHashes fillBlockHashesFn, fillMainChainHash fillMainChainHashFn, fillCheckPoint fillCheckPointFn) cache { 30 return cache{ 31 lruBlockHeaders: common.NewCache(maxCachedBlockHeaders), 32 lruBlockTxs: common.NewCache(maxCachedBlockTransactions), 33 lruBlockHashes: common.NewCache(maxCachedBlockHashes), 34 lruMainChainHashes: common.NewCache(maxCachedMainChainHashes), 35 lruCheckPoints: common.NewCache(maxCheckPoints), 36 37 fillBlockHeaderFn: fillBlockHeader, 38 fillBlockTransactionFn: fillBlockTxs, 39 fillBlockHashesFn: fillBlockHashes, 40 fillMainChainHashFn: fillMainChainHash, 41 fillCheckPointFn: fillCheckPoint, 42 } 43 } 44 45 type cache struct { 46 lruBlockHeaders *common.Cache 47 lruBlockTxs *common.Cache 48 lruBlockHashes *common.Cache 49 lruMainChainHashes *common.Cache 50 lruCheckPoints *common.Cache 51 52 fillBlockHashesFn func(uint64) ([]*bc.Hash, error) 53 fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error) 54 fillBlockHeaderFn func(hash *bc.Hash) (*types.BlockHeader, error) 55 fillMainChainHashFn func(uint64) (*bc.Hash, error) 56 fillCheckPointFn func(key []byte) (*state.Checkpoint, error) 57 58 sf singleflight.Group 59 } 60 61 func (c *cache) removeBlockHeader(blockHeader *types.BlockHeader) { 62 c.lruBlockHeaders.Remove(blockHeader.Hash()) 63 } 64 65 func (c *cache) lookupBlockHashesByHeight(height uint64) ([]*bc.Hash, error) { 66 if hashes, ok := c.lruBlockHashes.Get(height); ok { 67 return hashes.([]*bc.Hash), nil 68 } 69 70 heightStr := strconv.FormatUint(height, 10) 71 hashes, err := c.sf.Do("BlockHashesByHeight:"+heightStr, func() (interface{}, error) { 72 hashes, err := c.fillBlockHashesFn(height) 73 if err != nil { 74 return nil, err 75 } 76 77 c.lruBlockHashes.Add(height, hashes) 78 return hashes, nil 79 }) 80 if err != nil { 81 return nil, err 82 } 83 84 return hashes.([]*bc.Hash), nil 85 } 86 87 func (c *cache) removeBlockHashes(height uint64) { 88 c.lruBlockHashes.Remove(height) 89 } 90 91 func (c *cache) lookupBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { 92 if data, ok := c.lruBlockHeaders.Get(*hash); ok { 93 return data.(*types.BlockHeader), nil 94 } 95 96 blockHeader, err := c.sf.Do("BlockHeader:"+hash.String(), func() (interface{}, error) { 97 blockHeader, err := c.fillBlockHeaderFn(hash) 98 if err != nil { 99 return nil, err 100 } 101 102 c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader) 103 return blockHeader, nil 104 }) 105 if err != nil { 106 return nil, err 107 } 108 return blockHeader.(*types.BlockHeader), nil 109 } 110 111 func (c *cache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) { 112 if data, ok := c.lruBlockTxs.Get(*hash); ok { 113 return data.([]*types.Tx), nil 114 } 115 116 blockTxs, err := c.sf.Do("BlockTxs:"+hash.String(), func() (interface{}, error) { 117 blockTxs, err := c.fillBlockTransactionFn(hash) 118 if err != nil { 119 return nil, err 120 } 121 122 c.lruBlockTxs.Add(*hash, blockTxs) 123 return blockTxs, nil 124 }) 125 if err != nil { 126 return nil, err 127 } 128 return blockTxs.([]*types.Tx), nil 129 } 130 131 func (c *cache) lookupMainChainHash(height uint64) (*bc.Hash, error) { 132 if hash, ok := c.lruMainChainHashes.Get(height); ok { 133 return hash.(*bc.Hash), nil 134 } 135 136 heightStr := strconv.FormatUint(height, 10) 137 hash, err := c.sf.Do("BlockHashByHeight:"+heightStr, func() (interface{}, error) { 138 hash, err := c.fillMainChainHashFn(height) 139 if err != nil { 140 return nil, err 141 } 142 143 c.lruMainChainHashes.Add(height, hash) 144 return hash, nil 145 }) 146 if err != nil { 147 return nil, err 148 } 149 150 return hash.(*bc.Hash), nil 151 } 152 153 func (c *cache) removeMainChainHash(height uint64) { 154 c.lruMainChainHashes.Remove(height) 155 } 156 157 func (c *cache) lookupCheckPoint(key []byte) (*state.Checkpoint, error) { 158 keyStr := hex.EncodeToString(key) 159 if data, ok := c.lruCheckPoints.Get(keyStr); ok { 160 return data.(*state.Checkpoint), nil 161 } 162 163 checkpoint, err := c.sf.Do("CheckPoint:"+string(key), func() (interface{}, error) { 164 checkPoint, err := c.fillCheckPointFn(key) 165 if err != nil { 166 return nil, err 167 } 168 169 c.lruCheckPoints.Add(keyStr, checkPoint) 170 return checkPoint, nil 171 }) 172 if err != nil { 173 return nil, err 174 } 175 176 return checkpoint.(*state.Checkpoint), nil 177 } 178 179 func (c *cache) removeCheckPoint(key []byte) { 180 c.lruCheckPoints.Remove(hex.EncodeToString(key)) 181 }