github.com/klaytn/klaytn@v1.12.1/snapshot/wipe.go (about)

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