github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/les/pruner.go (about) 1 // Copyright 2019 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 les 18 19 import ( 20 "sync" 21 "time" 22 23 "github.com/kisexp/xdchain/common/math" 24 "github.com/kisexp/xdchain/core" 25 "github.com/kisexp/xdchain/ethdb" 26 "github.com/kisexp/xdchain/log" 27 ) 28 29 // pruner is responsible for pruning historical light chain data. 30 type pruner struct { 31 db ethdb.Database 32 indexers []*core.ChainIndexer 33 closeCh chan struct{} 34 wg sync.WaitGroup 35 } 36 37 // newPruner returns a light chain pruner instance. 38 func newPruner(db ethdb.Database, indexers ...*core.ChainIndexer) *pruner { 39 pruner := &pruner{ 40 db: db, 41 indexers: indexers, 42 closeCh: make(chan struct{}), 43 } 44 pruner.wg.Add(1) 45 go pruner.loop() 46 return pruner 47 } 48 49 // close notifies all background goroutines belonging to pruner to exit. 50 func (p *pruner) close() { 51 close(p.closeCh) 52 p.wg.Wait() 53 } 54 55 // loop periodically queries the status of chain indexers and prunes useless 56 // historical chain data. Notably, whenever Geth restarts, it will iterate 57 // all historical sections even they don't exist at all(below checkpoint) so 58 // that light client can prune cached chain data that was ODRed after pruning 59 // that section. 60 func (p *pruner) loop() { 61 defer p.wg.Done() 62 63 // cleanTicker is the ticker used to trigger a history clean 2 times a day. 64 var cleanTicker = time.NewTicker(12 * time.Hour) 65 66 // pruning finds the sections that have been processed by all indexers 67 // and deletes all historical chain data. 68 // Note, if some indexers don't support pruning(e.g. eth.BloomIndexer), 69 // pruning operations can be silently ignored. 70 pruning := func() { 71 min := uint64(math.MaxUint64) 72 for _, indexer := range p.indexers { 73 sections, _, _ := indexer.Sections() 74 if sections < min { 75 min = sections 76 } 77 } 78 // Always keep the latest section data in database. 79 if min < 2 || len(p.indexers) == 0 { 80 return 81 } 82 for _, indexer := range p.indexers { 83 if err := indexer.Prune(min - 2); err != nil { 84 log.Debug("Failed to prune historical data", "err", err) 85 return 86 } 87 } 88 p.db.Compact(nil, nil) // Compact entire database, ensure all removed data are deleted. 89 } 90 for { 91 pruning() 92 select { 93 case <-cleanTicker.C: 94 case <-p.closeCh: 95 return 96 } 97 } 98 }