github.com/klaytn/klaytn@v1.12.1/storage/database/cache_manager.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package database 18 19 import ( 20 "math/big" 21 "reflect" 22 23 "github.com/klaytn/klaytn/blockchain/types" 24 "github.com/klaytn/klaytn/common" 25 "github.com/klaytn/klaytn/rlp" 26 ) 27 28 // NOTE-Klaytn-Cache BlockChain Caches 29 // Below is the list of the constants for cache size. 30 // TODO-Klaytn: Below should be handled by ini or other configurations. 31 const ( 32 maxHeaderCache = 512 33 maxTdCache = 1024 34 maxBlockNumberCache = 2048 35 maxCanonicalHashCache = 2048 36 37 maxBodyCache = 256 38 maxBlockCache = 256 39 maxRecentTransactions = 30000 40 maxRecentBlockReceipts = 30 41 maxRecentTxReceipt = 30000 42 maxSenderTxHashToTxHash = 30000 43 ) 44 45 const ( 46 numShardsHeaderCache = 4096 47 numShardsTdCache = 4096 48 numShardsBlockNumberCache = 4096 49 numShardsCanonicalHashCache = 4096 50 51 numShardsBodyCache = 4096 52 numShardsBlockCache = 4096 53 numShardsRecentTransactions = 4096 54 numShardsRecentBlockReceipts = 4096 55 numShardsRecentTxReceipt = 4096 56 numShardsSenderTxHashToTxHash = 4096 57 ) 58 59 type cacheKey int 60 61 const ( 62 headerCacheIndex cacheKey = iota 63 tdCacheIndex 64 blockNumberCacheIndex 65 canonicalCacheIndex 66 67 bodyCacheIndex 68 bodyRLPCacheIndex 69 blockCacheIndex 70 recentTxAndLookupInfoIndex 71 recentBlockReceiptsIndex 72 recentTxReceiptIndex 73 senderTxHashToTxHashIndex 74 75 cacheKeySize 76 ) 77 78 var lruCacheConfig = [cacheKeySize]common.CacheConfiger{ 79 headerCacheIndex: common.LRUConfig{CacheSize: maxHeaderCache, IsScaled: true}, 80 tdCacheIndex: common.LRUConfig{CacheSize: maxTdCache, IsScaled: true}, 81 blockNumberCacheIndex: common.LRUConfig{CacheSize: maxBlockNumberCache, IsScaled: true}, 82 canonicalCacheIndex: common.LRUConfig{CacheSize: maxCanonicalHashCache, IsScaled: true}, 83 84 bodyCacheIndex: common.LRUConfig{CacheSize: maxBodyCache, IsScaled: true}, 85 bodyRLPCacheIndex: common.LRUConfig{CacheSize: maxBodyCache, IsScaled: true}, 86 blockCacheIndex: common.LRUConfig{CacheSize: maxBlockCache, IsScaled: true}, 87 recentTxAndLookupInfoIndex: common.LRUConfig{CacheSize: maxRecentTransactions, IsScaled: true}, 88 recentBlockReceiptsIndex: common.LRUConfig{CacheSize: maxRecentBlockReceipts, IsScaled: true}, 89 recentTxReceiptIndex: common.LRUConfig{CacheSize: maxRecentTxReceipt, IsScaled: true}, 90 senderTxHashToTxHashIndex: common.LRUConfig{CacheSize: maxSenderTxHashToTxHash, IsScaled: true}, 91 } 92 93 var lruShardCacheConfig = [cacheKeySize]common.CacheConfiger{ 94 headerCacheIndex: common.LRUShardConfig{CacheSize: maxHeaderCache, NumShards: numShardsHeaderCache, IsScaled: true}, 95 tdCacheIndex: common.LRUShardConfig{CacheSize: maxTdCache, NumShards: numShardsTdCache, IsScaled: true}, 96 blockNumberCacheIndex: common.LRUShardConfig{CacheSize: maxBlockNumberCache, NumShards: numShardsBlockNumberCache, IsScaled: true}, 97 canonicalCacheIndex: common.LRUShardConfig{CacheSize: maxCanonicalHashCache, NumShards: numShardsCanonicalHashCache, IsScaled: true}, 98 99 bodyCacheIndex: common.LRUShardConfig{CacheSize: maxBodyCache, NumShards: numShardsBodyCache, IsScaled: true}, 100 bodyRLPCacheIndex: common.LRUShardConfig{CacheSize: maxBodyCache, NumShards: numShardsBodyCache, IsScaled: true}, 101 blockCacheIndex: common.LRUShardConfig{CacheSize: maxBlockCache, NumShards: numShardsBlockCache, IsScaled: true}, 102 recentTxAndLookupInfoIndex: common.LRUShardConfig{CacheSize: maxRecentTransactions, NumShards: numShardsRecentTransactions, IsScaled: true}, 103 recentBlockReceiptsIndex: common.LRUShardConfig{CacheSize: maxRecentBlockReceipts, NumShards: numShardsRecentBlockReceipts, IsScaled: true}, 104 recentTxReceiptIndex: common.LRUShardConfig{CacheSize: maxRecentTxReceipt, NumShards: numShardsRecentTxReceipt, IsScaled: true}, 105 senderTxHashToTxHashIndex: common.LRUShardConfig{CacheSize: maxSenderTxHashToTxHash, NumShards: numShardsSenderTxHashToTxHash, IsScaled: true}, 106 } 107 108 var fifoCacheConfig = [cacheKeySize]common.CacheConfiger{ 109 headerCacheIndex: common.FIFOCacheConfig{CacheSize: maxHeaderCache, IsScaled: true}, 110 tdCacheIndex: common.FIFOCacheConfig{CacheSize: maxTdCache, IsScaled: true}, 111 blockNumberCacheIndex: common.FIFOCacheConfig{CacheSize: maxBlockNumberCache, IsScaled: true}, 112 canonicalCacheIndex: common.FIFOCacheConfig{CacheSize: maxCanonicalHashCache, IsScaled: true}, 113 114 bodyCacheIndex: common.FIFOCacheConfig{CacheSize: maxBodyCache, IsScaled: true}, 115 bodyRLPCacheIndex: common.FIFOCacheConfig{CacheSize: maxBodyCache, IsScaled: true}, 116 blockCacheIndex: common.FIFOCacheConfig{CacheSize: maxBlockCache, IsScaled: true}, 117 recentTxAndLookupInfoIndex: common.FIFOCacheConfig{CacheSize: maxRecentTransactions, IsScaled: true}, 118 recentBlockReceiptsIndex: common.FIFOCacheConfig{CacheSize: maxRecentBlockReceipts, IsScaled: true}, 119 recentTxReceiptIndex: common.FIFOCacheConfig{CacheSize: maxRecentTxReceipt, IsScaled: true}, 120 senderTxHashToTxHashIndex: common.FIFOCacheConfig{CacheSize: maxSenderTxHashToTxHash, IsScaled: true}, 121 } 122 123 func newCache(cacheNameKey cacheKey, cacheType common.CacheType) common.Cache { 124 var cache common.Cache 125 126 switch cacheType { 127 case common.FIFOCacheType: 128 cache = common.NewCache(fifoCacheConfig[cacheNameKey]) 129 case common.LRUCacheType: 130 cache = common.NewCache(lruCacheConfig[cacheNameKey]) 131 case common.LRUShardCacheType: 132 cache = common.NewCache(lruShardCacheConfig[cacheNameKey]) 133 default: 134 cache = common.NewCache(fifoCacheConfig[cacheNameKey]) 135 } 136 return cache 137 } 138 139 type TransactionLookup struct { 140 Tx *types.Transaction 141 *TxLookupEntry 142 } 143 144 // cacheManager handles caches of data structures stored in Database. 145 // Previously, most of them were handled by blockchain.HeaderChain or 146 // blockchain.BlockChain. 147 type cacheManager struct { 148 // caches from blockchain.HeaderChain 149 headerCache common.Cache 150 tdCache common.Cache 151 blockNumberCache common.Cache 152 canonicalHashCache common.Cache 153 154 // caches from blockchain.BlockChain 155 bodyCache common.Cache // Cache for the most recent block bodies 156 bodyRLPCache common.Cache // Cache for the most recent block bodies in RLP encoded format 157 blockCache common.Cache // Cache for the most recent entire blocks 158 recentTxAndLookupInfo common.Cache // recent TX and LookupInfo cache 159 recentBlockReceipts common.Cache // recent block receipts cache 160 recentTxReceipt common.Cache // recent TX receipt cache 161 162 senderTxHashToTxHashCache common.Cache 163 } 164 165 // newCacheManager returns a pointer of cacheManager with predefined configurations. 166 func newCacheManager() *cacheManager { 167 cm := &cacheManager{ 168 headerCache: newCache(headerCacheIndex, common.DefaultCacheType), 169 tdCache: newCache(tdCacheIndex, common.DefaultCacheType), 170 blockNumberCache: newCache(blockNumberCacheIndex, common.DefaultCacheType), 171 canonicalHashCache: newCache(canonicalCacheIndex, common.DefaultCacheType), 172 173 bodyCache: newCache(bodyCacheIndex, common.DefaultCacheType), 174 bodyRLPCache: newCache(bodyRLPCacheIndex, common.DefaultCacheType), 175 blockCache: newCache(blockCacheIndex, common.DefaultCacheType), 176 177 recentTxAndLookupInfo: newCache(recentTxAndLookupInfoIndex, common.DefaultCacheType), 178 recentBlockReceipts: newCache(recentBlockReceiptsIndex, common.DefaultCacheType), 179 recentTxReceipt: newCache(recentTxReceiptIndex, common.DefaultCacheType), 180 181 senderTxHashToTxHashCache: newCache(recentTxReceiptIndex, common.DefaultCacheType), 182 } 183 return cm 184 } 185 186 // clearHeaderChainCache flushes out 1) headerCache, 2) tdCache and 3) blockNumberCache. 187 func (cm *cacheManager) clearHeaderChainCache() { 188 cm.headerCache.Purge() 189 cm.tdCache.Purge() 190 cm.blockNumberCache.Purge() 191 cm.canonicalHashCache.Purge() 192 } 193 194 // clearBlockChainCache flushes out 1) bodyCache, 2) bodyRLPCache, 3) blockCache, 195 // 4) recentTxAndLookupInfo, 5) recentBlockReceipts and 6) recentTxReceipt. 196 func (cm *cacheManager) clearBlockChainCache() { 197 cm.bodyCache.Purge() 198 cm.bodyRLPCache.Purge() 199 cm.blockCache.Purge() 200 cm.recentTxAndLookupInfo.Purge() 201 cm.recentBlockReceipts.Purge() 202 cm.recentTxReceipt.Purge() 203 cm.senderTxHashToTxHashCache.Purge() 204 } 205 206 // readHeaderCache looks for cached header in headerCache. 207 // It returns nil if not found. 208 func (cm *cacheManager) readHeaderCache(hash common.Hash) *types.Header { 209 if header, ok := cm.headerCache.Get(hash); ok && header != nil { 210 cacheGetHeaderHitMeter.Mark(1) 211 return header.(*types.Header) 212 } 213 cacheGetHeaderMissMeter.Mark(1) 214 return nil 215 } 216 217 // writeHeaderCache writes header as a value, headerHash as a key. 218 func (cm *cacheManager) writeHeaderCache(hash common.Hash, header *types.Header) { 219 if header == nil { 220 return 221 } 222 cm.headerCache.Add(hash, header) 223 } 224 225 // deleteHeaderCache writes nil as a value, headerHash as a key, to indicate given 226 // headerHash is deleted in headerCache. 227 func (cm *cacheManager) deleteHeaderCache(hash common.Hash) { 228 cm.headerCache.Add(hash, nil) 229 } 230 231 // hasHeaderInCache returns if a cachedHeader exists with given headerHash. 232 func (cm *cacheManager) hasHeaderInCache(hash common.Hash) bool { 233 if cached, ok := cm.headerCache.Get(hash); ok && cached != nil { 234 return true 235 } 236 return false 237 } 238 239 // readTdCache looks for cached total blockScore in tdCache. 240 // It returns nil if not found. 241 func (cm *cacheManager) readTdCache(hash common.Hash) *big.Int { 242 if cached, ok := cm.tdCache.Get(hash); ok && cached != nil { 243 cacheGetTDHitMeter.Mark(1) 244 return cached.(*big.Int) 245 } 246 cacheGetTDMissMeter.Mark(1) 247 return nil 248 } 249 250 // writeHeaderCache writes total blockScore as a value, headerHash as a key. 251 func (cm *cacheManager) writeTdCache(hash common.Hash, td *big.Int) { 252 if td == nil { 253 return 254 } 255 cm.tdCache.Add(hash, td) 256 } 257 258 // deleteTdCache writes nil as a value, headerHash as a key, to indicate given 259 // headerHash is deleted in TdCache. 260 func (cm *cacheManager) deleteTdCache(hash common.Hash) { 261 cm.tdCache.Add(hash, nil) 262 } 263 264 // readBlockNumberCache looks for cached headerNumber in blockNumberCache. 265 // It returns nil if not found. 266 func (cm *cacheManager) readBlockNumberCache(hash common.Hash) *uint64 { 267 if cached, ok := cm.blockNumberCache.Get(hash); ok && cached != nil { 268 cacheGetBlockNumberHitMeter.Mark(1) 269 blockNumber := cached.(uint64) 270 return &blockNumber 271 } 272 cacheGetBlockNumberMissMeter.Mark(1) 273 return nil 274 } 275 276 // writeHeaderCache writes headerNumber as a value, headerHash as a key. 277 func (cm *cacheManager) writeBlockNumberCache(hash common.Hash, number uint64) { 278 cm.blockNumberCache.Add(hash, number) 279 } 280 281 // deleteBlockNumberCache deletes headerNumber with a headerHash as a key. 282 func (cm *cacheManager) deleteBlockNumberCache(hash common.Hash) { 283 cm.blockNumberCache.Add(hash, nil) 284 } 285 286 // readCanonicalHashCache looks for cached canonical hash in canonicalHashCache. 287 // It returns empty hash if not found. 288 func (cm *cacheManager) readCanonicalHashCache(number uint64) common.Hash { 289 if cached, ok := cm.canonicalHashCache.Get(common.CacheKeyUint64(number)); ok { 290 cacheGetCanonicalHashHitMeter.Mark(1) 291 canonicalHash := cached.(common.Hash) 292 return canonicalHash 293 } 294 cacheGetCanonicalHashMissMeter.Mark(1) 295 return common.Hash{} 296 } 297 298 // writeCanonicalHashCache writes canonical hash as a value, headerNumber as a key. 299 func (cm *cacheManager) writeCanonicalHashCache(number uint64, hash common.Hash) { 300 cm.canonicalHashCache.Add(common.CacheKeyUint64(number), hash) 301 } 302 303 // readBodyCache looks for cached blockBody in bodyCache. 304 // It returns nil if not found. 305 func (cm *cacheManager) readBodyCache(hash common.Hash) *types.Body { 306 if cachedBody, ok := cm.bodyCache.Get(hash); ok && cachedBody != nil { 307 cacheGetBlockBodyHitMeter.Mark(1) 308 return cachedBody.(*types.Body) 309 } 310 cacheGetBlockBodyMissMeter.Mark(1) 311 return nil 312 } 313 314 // writeBodyCache writes blockBody as a value, blockHash as a key. 315 func (cm *cacheManager) writeBodyCache(hash common.Hash, body *types.Body) { 316 if body == nil { 317 return 318 } 319 cm.bodyCache.Add(hash, body) 320 } 321 322 // deleteBodyCache writes nil as a value, blockHash as a key, to indicate given 323 // txHash is deleted in bodyCache and bodyRLPCache. 324 func (cm *cacheManager) deleteBodyCache(hash common.Hash) { 325 cm.bodyCache.Add(hash, nil) 326 cm.bodyRLPCache.Add(hash, nil) 327 } 328 329 // readBodyRLPCache looks for cached RLP-encoded blockBody in bodyRLPCache. 330 // It returns nil if not found. 331 func (cm *cacheManager) readBodyRLPCache(hash common.Hash) rlp.RawValue { 332 if cachedBodyRLP, ok := cm.bodyRLPCache.Get(hash); ok && cachedBodyRLP != nil { 333 cacheGetBlockBodyRLPHitMeter.Mark(1) 334 return cachedBodyRLP.(rlp.RawValue) 335 } 336 cacheGetBlockBodyRLPMissMeter.Mark(1) 337 return nil 338 } 339 340 // writeBodyRLPCache writes RLP-encoded blockBody as a value, blockHash as a key. 341 func (cm *cacheManager) writeBodyRLPCache(hash common.Hash, bodyRLP rlp.RawValue) { 342 if bodyRLP == nil { 343 return 344 } 345 cm.bodyRLPCache.Add(hash, bodyRLP) 346 } 347 348 // readBlockCache looks for cached block in blockCache. 349 // It returns nil if not found. 350 func (cm *cacheManager) readBlockCache(hash common.Hash) *types.Block { 351 if cachedBlock, ok := cm.blockCache.Get(hash); ok && cachedBlock != nil { 352 cacheGetBlockHitMeter.Mark(1) 353 return cachedBlock.(*types.Block) 354 } 355 cacheGetBlockMissMeter.Mark(1) 356 return nil 357 } 358 359 // hasBlockInCache returns if given hash exists in blockCache. 360 func (cm *cacheManager) hasBlockInCache(hash common.Hash) bool { 361 if cachedBlock, ok := cm.blockCache.Get(hash); ok && cachedBlock != nil { 362 return true 363 } 364 return false 365 } 366 367 // writeBlockCache writes block as a value, blockHash as a key. 368 func (cm *cacheManager) writeBlockCache(hash common.Hash, block *types.Block) { 369 if block == nil { 370 return 371 } 372 cm.blockCache.Add(hash, block) 373 } 374 375 // deleteBlockCache writes nil as a value, blockHash as a key, 376 // to indicate given blockHash is deleted in recentBlockReceipts. 377 func (cm *cacheManager) deleteBlockCache(hash common.Hash) { 378 cm.blockCache.Add(hash, nil) 379 } 380 381 // readTxAndLookupInfoInCache looks for cached tx and its look up information in recentTxAndLookupInfo. 382 // It returns nil and empty values if not found. 383 func (cm *cacheManager) readTxAndLookupInfoInCache(txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { 384 if value, ok := cm.recentTxAndLookupInfo.Get(txHash); ok && value != nil { 385 cacheGetRecentTransactionsHitMeter.Mark(1) 386 txLookup, ok := value.(*TransactionLookup) 387 if !ok { 388 logger.Error("invalid type in recentTxAndLookupInfo. expected=*TransactionLookup", "actual=", reflect.TypeOf(value)) 389 return nil, common.Hash{}, 0, 0 390 } 391 return txLookup.Tx, txLookup.BlockHash, txLookup.BlockIndex, txLookup.Index 392 } 393 cacheGetRecentTransactionsMissMeter.Mark(1) 394 return nil, common.Hash{}, 0, 0 395 } 396 397 // writeTxAndLookupInfoCache writes a tx and its lookup information as a value, txHash as a key. 398 func (cm *cacheManager) writeTxAndLookupInfoCache(txHash common.Hash, txLookup *TransactionLookup) { 399 if txLookup == nil { 400 return 401 } 402 cm.recentTxAndLookupInfo.Add(txHash, txLookup) 403 } 404 405 // readBlockReceiptsInCache looks for cached blockReceipts in recentBlockReceipts. 406 // It returns nil if not found. 407 func (cm *cacheManager) readBlockReceiptsInCache(blockHash common.Hash) types.Receipts { 408 if cachedBlockReceipts, ok := cm.recentBlockReceipts.Get(blockHash); ok && cachedBlockReceipts != nil { 409 cacheGetRecentBlockReceiptsHitMeter.Mark(1) 410 return cachedBlockReceipts.(types.Receipts) 411 } 412 cacheGetRecentBlockReceiptsMissMeter.Mark(1) 413 return nil 414 } 415 416 // writeBlockReceiptsCache writes blockReceipts as a value, blockHash as a key. 417 func (cm *cacheManager) writeBlockReceiptsCache(blockHash common.Hash, receipts types.Receipts) { 418 if receipts == nil { 419 return 420 } 421 cm.recentBlockReceipts.Add(blockHash, receipts) 422 } 423 424 // deleteBlockReceiptsCache writes nil as a value, blockHash as a key, to indicate given 425 // blockHash is deleted in recentBlockReceipts. 426 func (cm *cacheManager) deleteBlockReceiptsCache(blockHash common.Hash) { 427 cm.recentBlockReceipts.Add(blockHash, nil) 428 } 429 430 // readTxReceiptInCache looks for cached txReceipt in recentTxReceipt. 431 // It returns nil if not found. 432 func (cm *cacheManager) readTxReceiptInCache(txHash common.Hash) *types.Receipt { 433 if cachedReceipt, ok := cm.recentTxReceipt.Get(txHash); ok && cachedReceipt != nil { 434 cacheGetRecentTxReceiptHitMeter.Mark(1) 435 return cachedReceipt.(*types.Receipt) 436 } 437 cacheGetRecentTxReceiptMissMeter.Mark(1) 438 return nil 439 } 440 441 // writeTxReceiptCache writes txReceipt as a value, txHash as a key. 442 func (cm *cacheManager) writeTxReceiptCache(txHash common.Hash, receipt *types.Receipt) { 443 if receipt == nil { 444 return 445 } 446 cm.recentTxReceipt.Add(txHash, receipt) 447 } 448 449 // deleteTxReceiptCache writes nil as a value, blockHash as a key, to indicate given 450 // txHash is deleted in recentTxReceipt. 451 func (cm *cacheManager) deleteTxReceiptCache(txHash common.Hash) { 452 cm.recentTxReceipt.Add(txHash, nil) 453 } 454 455 // writeSenderTxHashToTxHashCache writes senderTxHash to txHash mapping information to cache. 456 func (cm *cacheManager) writeSenderTxHashToTxHashCache(senderTxHash, txHash common.Hash) { 457 cm.senderTxHashToTxHashCache.Add(senderTxHash, txHash) 458 } 459 460 // readSenderTxHashToTxHashCache looks for matching txHash from senderTxHash. 461 // If txHash does not exist in the cache, it returns an empty hash. 462 func (cm *cacheManager) readSenderTxHashToTxHashCache(senderTxHash common.Hash) common.Hash { 463 if matchedTxHash, ok := cm.senderTxHashToTxHashCache.Get(senderTxHash); ok && matchedTxHash != nil { 464 return matchedTxHash.(common.Hash) 465 } 466 return common.Hash{} 467 }