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}