github.com/amazechain/amc@v0.1.3/modules/ethdb/walk.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethdb
    18  
    19  import (
    20  	"bytes"
    21  
    22  	"github.com/ledgerwatch/erigon-lib/kv"
    23  )
    24  
    25  // splitCursor implements cursor with two keys
    26  // it is used to ignore incarnations in the middle
    27  // of composite storage key, but without
    28  // reconstructing the key
    29  // Instead, the key is split into two parts and
    30  // functions `Seek` and `Next` deliver both
    31  // parts as well as the corresponding value
    32  type splitCursor struct {
    33  	c          kv.Cursor // Unlerlying cursor
    34  	startkey   []byte    // Starting key (also contains bits that need to be preserved)
    35  	matchBytes int
    36  	mask       uint8
    37  	part1end   int // Position in the key where the first part ends
    38  	part2start int // Position in the key where the second part starts
    39  	part3start int // Position in the key where the third part starts
    40  }
    41  
    42  func NewSplitCursor(c kv.Cursor, startkey []byte, matchBits int, part1end, part2start, part3start int) *splitCursor {
    43  	var sc splitCursor
    44  	sc.c = c
    45  	sc.startkey = startkey
    46  	sc.part1end = part1end
    47  	sc.part2start = part2start
    48  	sc.part3start = part3start
    49  	sc.matchBytes, sc.mask = Bytesmask(matchBits)
    50  	return &sc
    51  }
    52  
    53  func (sc *splitCursor) matchKey(k []byte) bool {
    54  	if k == nil {
    55  		return false
    56  	}
    57  	if sc.matchBytes == 0 {
    58  		return true
    59  	}
    60  	if len(k) < sc.matchBytes {
    61  		return false
    62  	}
    63  	if !bytes.Equal(k[:sc.matchBytes-1], sc.startkey[:sc.matchBytes-1]) {
    64  		return false
    65  	}
    66  	return (k[sc.matchBytes-1] & sc.mask) == (sc.startkey[sc.matchBytes-1] & sc.mask)
    67  }
    68  
    69  func (sc *splitCursor) Seek() (key1, key2, key3, val []byte, err error) {
    70  	k, v, err1 := sc.c.Seek(sc.startkey)
    71  	if err1 != nil {
    72  		return nil, nil, nil, nil, err1
    73  	}
    74  	if !sc.matchKey(k) {
    75  		return nil, nil, nil, nil, nil
    76  	}
    77  	return k[:sc.part1end], k[sc.part2start:sc.part3start], k[sc.part3start:], v, nil
    78  }
    79  
    80  func (sc *splitCursor) Next() (key1, key2, key3, val []byte, err error) {
    81  	k, v, err1 := sc.c.Next()
    82  	if err1 != nil {
    83  		return nil, nil, nil, nil, err1
    84  	}
    85  	if !sc.matchKey(k) {
    86  		return nil, nil, nil, nil, nil
    87  	}
    88  	return k[:sc.part1end], k[sc.part2start:sc.part3start], k[sc.part3start:], v, nil
    89  }
    90  
    91  var EndSuffix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}