github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/core/state/snapshot/wipe.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 snapshot
    18  
    19  import (
    20  	"bytes"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/ethdb"
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/metrics"
    27  )
    28  
    29  // wipeKeyRange deletes a range of keys from the database starting with prefix
    30  // and having a specific total key length. The start and limit is optional for
    31  // specifying a particular key range for deletion.
    32  //
    33  // Origin is included for wiping and limit is excluded if they are specified.
    34  func wipeKeyRange(db ethdb.KeyValueStore, kind string, prefix []byte, origin []byte, limit []byte, keylen int, meter metrics.Meter, report bool) error {
    35  	// Batch deletions together to avoid holding an iterator for too long
    36  	var (
    37  		batch = db.NewBatch()
    38  		items int
    39  	)
    40  	// Iterate over the key-range and delete all of them
    41  	start, logged := time.Now(), time.Now()
    42  
    43  	it := db.NewIterator(prefix, origin)
    44  	var stop []byte
    45  	if limit != nil {
    46  		stop = append(prefix, limit...)
    47  	}
    48  	for it.Next() {
    49  		// Skip any keys with the correct prefix but wrong length (trie nodes)
    50  		key := it.Key()
    51  		if !bytes.HasPrefix(key, prefix) {
    52  			break
    53  		}
    54  		if len(key) != keylen {
    55  			continue
    56  		}
    57  		if stop != nil && bytes.Compare(key, stop) >= 0 {
    58  			break
    59  		}
    60  		// Delete the key and periodically recreate the batch and iterator
    61  		batch.Delete(key)
    62  		items++
    63  
    64  		if items%10000 == 0 {
    65  			// Batch too large (or iterator too long lived, flush and recreate)
    66  			it.Release()
    67  			if err := batch.Write(); err != nil {
    68  				return err
    69  			}
    70  			batch.Reset()
    71  			seekPos := key[len(prefix):]
    72  			it = db.NewIterator(prefix, seekPos)
    73  
    74  			if time.Since(logged) > 8*time.Second && report {
    75  				log.Info("Deleting state snapshot leftovers", "kind", kind, "wiped", items, "elapsed", common.PrettyDuration(time.Since(start)))
    76  				logged = time.Now()
    77  			}
    78  		}
    79  	}
    80  	it.Release()
    81  	if err := batch.Write(); err != nil {
    82  		return err
    83  	}
    84  	if meter != nil {
    85  		meter.Mark(int64(items))
    86  	}
    87  	if report {
    88  		log.Info("Deleted state snapshot leftovers", "kind", kind, "wiped", items, "elapsed", common.PrettyDuration(time.Since(start)))
    89  	}
    90  	return nil
    91  }