github.com/ethereum/go-ethereum@v1.14.3/core/state/snapshot/holdable_iterator.go (about)

     1  // Copyright 2022 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  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/ethdb"
    22  )
    23  
    24  // holdableIterator is a wrapper of underlying database iterator. It extends
    25  // the basic iterator interface by adding Hold which can hold the element
    26  // locally where the iterator is currently located and serve it up next time.
    27  type holdableIterator struct {
    28  	it     ethdb.Iterator
    29  	key    []byte
    30  	val    []byte
    31  	atHeld bool
    32  }
    33  
    34  // newHoldableIterator initializes the holdableIterator with the given iterator.
    35  func newHoldableIterator(it ethdb.Iterator) *holdableIterator {
    36  	return &holdableIterator{it: it}
    37  }
    38  
    39  // Hold holds the element locally where the iterator is currently located which
    40  // can be served up next time.
    41  func (it *holdableIterator) Hold() {
    42  	if it.it.Key() == nil {
    43  		return // nothing to hold
    44  	}
    45  	it.key = common.CopyBytes(it.it.Key())
    46  	it.val = common.CopyBytes(it.it.Value())
    47  	it.atHeld = false
    48  }
    49  
    50  // Next moves the iterator to the next key/value pair. It returns whether the
    51  // iterator is exhausted.
    52  func (it *holdableIterator) Next() bool {
    53  	if !it.atHeld && it.key != nil {
    54  		it.atHeld = true
    55  	} else if it.atHeld {
    56  		it.atHeld = false
    57  		it.key = nil
    58  		it.val = nil
    59  	}
    60  	if it.key != nil {
    61  		return true // shifted to locally held value
    62  	}
    63  	return it.it.Next()
    64  }
    65  
    66  // Error returns any accumulated error. Exhausting all the key/value pairs
    67  // is not considered to be an error.
    68  func (it *holdableIterator) Error() error { return it.it.Error() }
    69  
    70  // Release releases associated resources. Release should always succeed and can
    71  // be called multiple times without causing error.
    72  func (it *holdableIterator) Release() {
    73  	it.atHeld = false
    74  	it.key = nil
    75  	it.val = nil
    76  	it.it.Release()
    77  }
    78  
    79  // Key returns the key of the current key/value pair, or nil if done. The caller
    80  // should not modify the contents of the returned slice, and its contents may
    81  // change on the next call to Next.
    82  func (it *holdableIterator) Key() []byte {
    83  	if it.key != nil {
    84  		return it.key
    85  	}
    86  	return it.it.Key()
    87  }
    88  
    89  // Value returns the value of the current key/value pair, or nil if done. The
    90  // caller should not modify the contents of the returned slice, and its contents
    91  // may change on the next call to Next.
    92  func (it *holdableIterator) Value() []byte {
    93  	if it.val != nil {
    94  		return it.val
    95  	}
    96  	return it.it.Value()
    97  }