github.com/ledgerwatch/erigon-lib@v1.0.0/kv/temporal/historyv2/changeset.go (about) 1 /* 2 Copyright 2022 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package historyv2 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 math2 "math" 24 "reflect" 25 26 "github.com/ledgerwatch/erigon-lib/common/hexutility" 27 "github.com/ledgerwatch/erigon-lib/common/length" 28 "github.com/ledgerwatch/erigon-lib/kv" 29 ) 30 31 func NewChangeSet() *ChangeSet { 32 return &ChangeSet{ 33 Changes: make([]Change, 0), 34 } 35 } 36 37 type Change struct { 38 Key []byte 39 Value []byte 40 } 41 42 // ChangeSet is a map with keys of the same size. 43 // Both keys and values are byte strings. 44 type ChangeSet struct { 45 // Invariant: all keys are of the same size. 46 Changes []Change 47 keyLen int 48 } 49 50 // BEGIN sort.Interface 51 52 func (s *ChangeSet) Len() int { 53 return len(s.Changes) 54 } 55 56 func (s *ChangeSet) Swap(i, j int) { 57 s.Changes[i], s.Changes[j] = s.Changes[j], s.Changes[i] 58 } 59 60 func (s *ChangeSet) Less(i, j int) bool { 61 cmp := bytes.Compare(s.Changes[i].Key, s.Changes[j].Key) 62 if cmp == 0 { 63 cmp = bytes.Compare(s.Changes[i].Value, s.Changes[j].Value) 64 } 65 return cmp < 0 66 } 67 68 // END sort.Interface 69 func (s *ChangeSet) KeySize() int { 70 if s.keyLen != 0 { 71 return s.keyLen 72 } 73 for _, c := range s.Changes { 74 return len(c.Key) 75 } 76 return 0 77 } 78 79 func (s *ChangeSet) checkKeySize(key []byte) error { 80 if (s.Len() == 0 && s.KeySize() == 0) || (len(key) == s.KeySize() && len(key) > 0) { 81 return nil 82 } 83 84 return fmt.Errorf("wrong key size in AccountChangeSet: expected %d, actual %d", s.KeySize(), len(key)) 85 } 86 87 // Add adds a new entry to the AccountChangeSet. 88 // One must not add an existing key 89 // and may add keys only of the same size. 90 func (s *ChangeSet) Add(key []byte, value []byte) error { 91 if err := s.checkKeySize(key); err != nil { 92 return err 93 } 94 95 s.Changes = append(s.Changes, Change{ 96 Key: key, 97 Value: value, 98 }) 99 return nil 100 } 101 102 func (s *ChangeSet) ChangedKeys() map[string]struct{} { 103 m := make(map[string]struct{}, len(s.Changes)) 104 for i := range s.Changes { 105 m[string(s.Changes[i].Key)] = struct{}{} 106 } 107 return m 108 } 109 110 func (s *ChangeSet) Equals(s2 *ChangeSet) bool { 111 return reflect.DeepEqual(s.Changes, s2.Changes) 112 } 113 114 // Encoded Method 115 func FromDBFormat(dbKey, dbValue []byte) (uint64, []byte, []byte, error) { 116 if len(dbKey) == 8 { 117 return DecodeAccounts(dbKey, dbValue) 118 } else { 119 return DecodeStorage(dbKey, dbValue) 120 } 121 } 122 123 func AvailableFrom(tx kv.Tx) (uint64, error) { 124 c, err := tx.Cursor(kv.AccountChangeSet) 125 if err != nil { 126 return math2.MaxUint64, err 127 } 128 defer c.Close() 129 k, _, err := c.First() 130 if err != nil { 131 return math2.MaxUint64, err 132 } 133 if len(k) == 0 { 134 return math2.MaxUint64, nil 135 } 136 return binary.BigEndian.Uint64(k), nil 137 } 138 func AvailableStorageFrom(tx kv.Tx) (uint64, error) { 139 c, err := tx.Cursor(kv.StorageChangeSet) 140 if err != nil { 141 return math2.MaxUint64, err 142 } 143 defer c.Close() 144 k, _, err := c.First() 145 if err != nil { 146 return math2.MaxUint64, err 147 } 148 if len(k) == 0 { 149 return math2.MaxUint64, nil 150 } 151 return binary.BigEndian.Uint64(k), nil 152 } 153 154 func ForEach(db kv.Tx, bucket string, startkey []byte, walker func(blockN uint64, k, v []byte) error) error { 155 var blockN uint64 156 return db.ForEach(bucket, startkey, func(k, v []byte) error { 157 var err error 158 blockN, k, v, err = FromDBFormat(k, v) 159 if err != nil { 160 return err 161 } 162 return walker(blockN, k, v) 163 }) 164 } 165 func ForPrefix(db kv.Tx, bucket string, startkey []byte, walker func(blockN uint64, k, v []byte) error) error { 166 var blockN uint64 167 return db.ForPrefix(bucket, startkey, func(k, v []byte) error { 168 var err error 169 blockN, k, v, err = FromDBFormat(k, v) 170 if err != nil { 171 return err 172 } 173 return walker(blockN, k, v) 174 }) 175 } 176 177 func Truncate(tx kv.RwTx, from uint64) error { 178 keyStart := hexutility.EncodeTs(from) 179 180 { 181 c, err := tx.RwCursorDupSort(kv.AccountChangeSet) 182 if err != nil { 183 return err 184 } 185 defer c.Close() 186 for k, _, err := c.Seek(keyStart); k != nil; k, _, err = c.NextNoDup() { 187 if err != nil { 188 return err 189 } 190 if err = tx.Delete(kv.AccountChangeSet, k); err != nil { 191 return err 192 } 193 if err != nil { 194 return err 195 } 196 } 197 } 198 { 199 c, err := tx.RwCursorDupSort(kv.StorageChangeSet) 200 if err != nil { 201 return err 202 } 203 defer c.Close() 204 for k, _, err := c.Seek(keyStart); k != nil; k, _, err = c.NextNoDup() { 205 if err != nil { 206 return err 207 } 208 if err = tx.Delete(kv.StorageChangeSet, k); err != nil { 209 return err 210 } 211 } 212 } 213 return nil 214 } 215 216 type CSMapper struct { 217 IndexBucket string 218 IndexChunkKey func([]byte, uint64) []byte 219 Find func(cursor kv.CursorDupSort, blockNumber uint64, key []byte) ([]byte, error) 220 New func() *ChangeSet 221 Encode Encoder 222 Decode Decoder 223 } 224 225 var Mapper = map[string]CSMapper{ 226 kv.AccountChangeSet: { 227 IndexBucket: kv.E2AccountsHistory, 228 IndexChunkKey: AccountIndexChunkKey, 229 New: NewAccountChangeSet, 230 Find: FindAccount, 231 Encode: EncodeAccounts, 232 Decode: DecodeAccounts, 233 }, 234 kv.StorageChangeSet: { 235 IndexBucket: kv.E2StorageHistory, 236 IndexChunkKey: StorageIndexChunkKey, 237 Find: FindStorage, 238 New: NewStorageChangeSet, 239 Encode: EncodeStorage, 240 Decode: DecodeStorage, 241 }, 242 } 243 244 func AccountIndexChunkKey(key []byte, blockNumber uint64) []byte { 245 blockNumBytes := make([]byte, length.Addr+8) 246 copy(blockNumBytes, key) 247 binary.BigEndian.PutUint64(blockNumBytes[length.Addr:], blockNumber) 248 249 return blockNumBytes 250 } 251 252 func StorageIndexChunkKey(key []byte, blockNumber uint64) []byte { 253 //remove incarnation and add block number 254 blockNumBytes := make([]byte, length.Addr+length.Hash+8) 255 copy(blockNumBytes, key[:length.Addr]) 256 copy(blockNumBytes[length.Addr:], key[length.Addr+length.Incarnation:]) 257 binary.BigEndian.PutUint64(blockNumBytes[length.Addr+length.Hash:], blockNumber) 258 259 return blockNumBytes 260 }