github.com/klaytn/klaytn@v1.12.1/node/cn/bloombits.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/bloombits.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package cn 22 23 import ( 24 "time" 25 26 "github.com/klaytn/klaytn/blockchain" 27 "github.com/klaytn/klaytn/blockchain/bloombits" 28 "github.com/klaytn/klaytn/blockchain/types" 29 "github.com/klaytn/klaytn/common" 30 "github.com/klaytn/klaytn/common/bitutil" 31 "github.com/klaytn/klaytn/params" 32 "github.com/klaytn/klaytn/storage/database" 33 ) 34 35 const ( 36 // bloomServiceThreads is the number of goroutines used globally by a CN 37 // instance to service bloombits lookups for all running filters. 38 bloomServiceThreads = 16 39 40 // bloomFilterThreads is the number of goroutines used locally per filter to 41 // multiplex requests onto the global servicing goroutines. 42 bloomFilterThreads = 3 43 44 // bloomRetrievalBatch is the maximum number of bloom bit retrievals to service 45 // in a single batch. 46 bloomRetrievalBatch = 16 47 48 // bloomRetrievalWait is the maximum time to wait for enough bloom bit requests 49 // to accumulate request an entire batch (avoiding hysteresis). 50 bloomRetrievalWait = time.Duration(0) 51 ) 52 53 // startBloomHandlers starts a batch of goroutines to accept bloom bit database 54 // retrievals from possibly a range of filters and serving the data to satisfy. 55 func (cn *CN) startBloomHandlers() { 56 for i := 0; i < bloomServiceThreads; i++ { 57 go func() { 58 for { 59 select { 60 case <-cn.closeBloomHandler: 61 return 62 63 case request := <-cn.bloomRequests: 64 task := <-request 65 task.Bitsets = make([][]byte, len(task.Sections)) 66 for i, section := range task.Sections { 67 head := cn.chainDB.ReadCanonicalHash((section+1)*params.BloomBitsBlocks - 1) 68 if compVector, err := cn.chainDB.ReadBloomBits(database.BloomBitsKey(task.Bit, section, head)); err == nil { 69 if blob, err := bitutil.DecompressBytes(compVector, int(params.BloomBitsBlocks)/8); err == nil { 70 task.Bitsets[i] = blob 71 } else { 72 task.Error = err 73 } 74 } else { 75 task.Error = err 76 } 77 } 78 request <- task 79 } 80 } 81 }() 82 } 83 } 84 85 const ( 86 // bloomConfirms is the number of confirmation blocks before a bloom section is 87 // considered probably final and its rotated bits are calculated. 88 bloomConfirms = 256 89 90 // bloomThrottling is the time to wait between processing two consecutive index 91 // sections. It's useful during chain upgrades to prevent disk overload. 92 bloomThrottling = 100 * time.Millisecond 93 ) 94 95 // BloomIndexer implements a blockchain.ChainIndexer, building up a rotated bloom bits index 96 // for the Klaytn header bloom filters, permitting blazing fast filtering. 97 type BloomIndexer struct { 98 size uint64 // section size to generate bloombits for 99 100 db database.DBManager // database instance to write index data and metadata into 101 gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index 102 103 section uint64 // Section is the section number being processed currently 104 head common.Hash // Head is the hash of the last header processed 105 } 106 107 // NewBloomIndexer returns a chain indexer that generates bloom bits data for the 108 // canonical chain for fast logs filtering. 109 func NewBloomIndexer(db database.DBManager, size uint64) *blockchain.ChainIndexer { 110 backend := &BloomIndexer{ 111 db: db, 112 size: size, 113 } 114 115 return blockchain.NewChainIndexer(db, db, backend, size, bloomConfirms, bloomThrottling, "bloombits") 116 } 117 118 // Reset implements blockchain.ChainIndexerBackend, starting a new bloombits index 119 // section. 120 func (b *BloomIndexer) Reset(section uint64, lastSectionHead common.Hash) error { 121 gen, err := bloombits.NewGenerator(uint(b.size)) 122 b.gen, b.section, b.head = gen, section, common.Hash{} 123 return err 124 } 125 126 // Process implements blockchain.ChainIndexerBackend, adding a new header's bloom into 127 // the index. 128 func (b *BloomIndexer) Process(header *types.Header) { 129 b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom) 130 b.head = header.Hash() 131 } 132 133 // Commit implements blockchain.ChainIndexerBackend, finalizing the bloom section and 134 // writing it out into the database. 135 func (b *BloomIndexer) Commit() error { 136 batch := b.db.NewBatch(database.MiscDB) 137 defer batch.Release() 138 139 for i := 0; i < types.BloomBitLength; i++ { 140 bits, err := b.gen.Bitset(uint(i)) 141 if err != nil { 142 return err 143 } 144 err = batch.Put(database.BloomBitsKey(uint(i), b.section, b.head), bitutil.CompressBytes(bits)) 145 if err != nil { 146 logger.Crit("Failed to store bloom bits", "err", err) 147 } 148 } 149 return batch.Write() 150 }