github.com/ledgerwatch/erigon-lib@v1.0.0/kv/memdb/memory_mutation_cursor.go (about) 1 /* 2 Copyright 2022 Erigon contributors 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package memdb 15 16 import ( 17 "bytes" 18 "fmt" 19 20 "github.com/ledgerwatch/erigon-lib/common" 21 "github.com/ledgerwatch/erigon-lib/kv" 22 ) 23 24 type NextType int 25 26 const ( 27 Normal NextType = iota 28 Dup 29 NoDup 30 ) 31 32 // entry for the cursor 33 type cursorEntry struct { 34 key []byte 35 value []byte 36 } 37 38 // cursor 39 type memoryMutationCursor struct { 40 // entry history 41 cursor kv.CursorDupSort 42 memCursor kv.RwCursorDupSort 43 // we keep the mining mutation so that we can insert new elements in db 44 mutation *MemoryMutation 45 table string 46 currentPair cursorEntry 47 currentDbEntry cursorEntry 48 currentMemEntry cursorEntry 49 isPrevFromDb bool 50 } 51 52 func (m *memoryMutationCursor) isTableCleared() bool { 53 return m.mutation.isTableCleared(m.table) 54 } 55 56 func (m *memoryMutationCursor) isEntryDeleted(key []byte, value []byte, t NextType) bool { 57 if t == Normal { 58 return m.mutation.isEntryDeleted(m.table, key) 59 } else { 60 return m.mutation.isEntryDeleted(m.table, m.convertAutoDupsort(key, value)) 61 } 62 } 63 64 // First move cursor to first position and return key and value accordingly. 65 func (m *memoryMutationCursor) First() ([]byte, []byte, error) { 66 memKey, memValue, err := m.memCursor.First() 67 if err != nil || m.isTableCleared() { 68 return memKey, memValue, err 69 } 70 71 dbKey, dbValue, err := m.cursor.First() 72 if err != nil { 73 return nil, nil, err 74 } 75 76 if dbKey != nil && m.isEntryDeleted(dbKey, dbValue, Normal) { 77 if dbKey, dbValue, err = m.getNextOnDb(Normal); err != nil { 78 return nil, nil, err 79 } 80 } 81 82 return m.resolveCursorPriority(memKey, memValue, dbKey, dbValue, Normal) 83 } 84 85 func (m *memoryMutationCursor) getNextOnDb(t NextType) (key []byte, value []byte, err error) { 86 switch t { 87 case Normal: 88 key, value, err = m.cursor.Next() 89 if err != nil { 90 return 91 } 92 case Dup: 93 key, value, err = m.cursor.NextDup() 94 if err != nil { 95 return 96 } 97 case NoDup: 98 key, value, err = m.cursor.NextNoDup() 99 if err != nil { 100 return 101 } 102 default: 103 err = fmt.Errorf("invalid next type") 104 return 105 } 106 107 for key != nil && value != nil && m.isEntryDeleted(key, value, t) { 108 switch t { 109 case Normal: 110 key, value, err = m.cursor.Next() 111 if err != nil { 112 return 113 } 114 case Dup: 115 key, value, err = m.cursor.NextDup() 116 if err != nil { 117 return 118 } 119 case NoDup: 120 key, value, err = m.cursor.NextNoDup() 121 if err != nil { 122 return 123 } 124 default: 125 err = fmt.Errorf("invalid next type") 126 return 127 } 128 } 129 return 130 } 131 132 func (m *memoryMutationCursor) convertAutoDupsort(key []byte, value []byte) []byte { 133 config, ok := kv.ChaindataTablesCfg[m.table] 134 // If we do not have the configuration we assume it is not dupsorted 135 if !ok || !config.AutoDupSortKeysConversion { 136 return key 137 } 138 if len(key) != config.DupToLen { 139 return key 140 } 141 return append(key, value[:config.DupFromLen-config.DupToLen]...) 142 } 143 144 // Current return the current key and values the cursor is on. 145 func (m *memoryMutationCursor) Current() ([]byte, []byte, error) { 146 if m.isTableCleared() { 147 return m.memCursor.Current() 148 } 149 return common.Copy(m.currentPair.key), common.Copy(m.currentPair.value), nil 150 } 151 152 func (m *memoryMutationCursor) skipIntersection(memKey, memValue, dbKey, dbValue []byte, t NextType) (newDbKey []byte, newDbValue []byte, err error) { 153 newDbKey = dbKey 154 newDbValue = dbValue 155 config, ok := kv.ChaindataTablesCfg[m.table] 156 dupSortTable := ok && ((config.Flags & kv.DupSort) != 0) 157 autoKeyConversion := ok && config.AutoDupSortKeysConversion 158 dupsortOffset := 0 159 if autoKeyConversion { 160 dupsortOffset = config.DupFromLen - config.DupToLen 161 } 162 // Check for duplicates 163 if bytes.Equal(memKey, dbKey) { 164 var skip bool 165 if t == Normal { 166 skip = !dupSortTable || autoKeyConversion || bytes.Equal(memValue, dbValue) 167 } else { 168 skip = bytes.Equal(memValue, dbValue) || 169 (dupsortOffset != 0 && len(memValue) >= dupsortOffset && len(dbValue) >= dupsortOffset && bytes.Equal(memValue[:dupsortOffset], dbValue[:dupsortOffset])) 170 } 171 if skip { 172 if newDbKey, newDbValue, err = m.getNextOnDb(t); err != nil { 173 return 174 } 175 } 176 } 177 return 178 } 179 180 func (m *memoryMutationCursor) resolveCursorPriority(memKey, memValue, dbKey, dbValue []byte, t NextType) ([]byte, []byte, error) { 181 if memValue == nil && dbValue == nil { 182 return nil, nil, nil 183 } 184 185 var err error 186 dbKey, dbValue, err = m.skipIntersection(memKey, memValue, dbKey, dbValue, t) 187 if err != nil { 188 return nil, nil, err 189 } 190 191 m.currentDbEntry = cursorEntry{dbKey, dbValue} 192 m.currentMemEntry = cursorEntry{memKey, memValue} 193 // compare entries 194 if bytes.Equal(memKey, dbKey) { 195 m.isPrevFromDb = dbValue != nil && (memValue == nil || bytes.Compare(memValue, dbValue) > 0) 196 } else { 197 m.isPrevFromDb = dbValue != nil && (memKey == nil || bytes.Compare(memKey, dbKey) > 0) 198 } 199 if dbValue == nil { 200 m.currentDbEntry = cursorEntry{} 201 } 202 if memValue == nil { 203 m.currentMemEntry = cursorEntry{} 204 } 205 if m.isPrevFromDb { 206 m.currentPair = cursorEntry{dbKey, dbValue} 207 return dbKey, dbValue, nil 208 } 209 210 m.currentPair = cursorEntry{memKey, memValue} 211 return memKey, memValue, nil 212 } 213 214 // Next returns the next element of the mutation. 215 func (m *memoryMutationCursor) Next() ([]byte, []byte, error) { 216 if m.isTableCleared() { 217 return m.memCursor.Next() 218 } 219 220 if m.isPrevFromDb { 221 k, v, err := m.getNextOnDb(Normal) 222 if err != nil { 223 return nil, nil, err 224 } 225 return m.resolveCursorPriority(m.currentMemEntry.key, m.currentMemEntry.value, k, v, Normal) 226 } 227 228 memK, memV, err := m.memCursor.Next() 229 if err != nil { 230 return nil, nil, err 231 } 232 233 return m.resolveCursorPriority(memK, memV, m.currentDbEntry.key, m.currentDbEntry.value, Normal) 234 } 235 236 // NextDup returns the next element of the mutation. 237 func (m *memoryMutationCursor) NextDup() ([]byte, []byte, error) { 238 if m.isTableCleared() { 239 return m.memCursor.NextDup() 240 } 241 242 if m.isPrevFromDb { 243 k, v, err := m.getNextOnDb(Dup) 244 245 if err != nil { 246 return nil, nil, err 247 } 248 return m.resolveCursorPriority(m.currentMemEntry.key, m.currentMemEntry.value, k, v, Dup) 249 } 250 251 memK, memV, err := m.memCursor.NextDup() 252 if err != nil { 253 return nil, nil, err 254 } 255 256 return m.resolveCursorPriority(memK, memV, m.currentDbEntry.key, m.currentDbEntry.value, Dup) 257 } 258 259 // Seek move pointer to a key at a certain position. 260 func (m *memoryMutationCursor) Seek(seek []byte) ([]byte, []byte, error) { 261 if m.isTableCleared() { 262 return m.memCursor.Seek(seek) 263 } 264 265 dbKey, dbValue, err := m.cursor.Seek(seek) 266 if err != nil { 267 return nil, nil, err 268 } 269 270 // If the entry is marked as deleted find one that is not 271 if dbKey != nil && m.isEntryDeleted(dbKey, dbValue, Normal) { 272 dbKey, dbValue, err = m.getNextOnDb(Normal) 273 if err != nil { 274 return nil, nil, err 275 } 276 } 277 278 memKey, memValue, err := m.memCursor.Seek(seek) 279 if err != nil { 280 return nil, nil, err 281 } 282 283 return m.resolveCursorPriority(memKey, memValue, dbKey, dbValue, Normal) 284 } 285 286 // Seek move pointer to a key at a certain position. 287 func (m *memoryMutationCursor) SeekExact(seek []byte) ([]byte, []byte, error) { 288 memKey, memValue, err := m.memCursor.SeekExact(seek) 289 if err != nil || m.isTableCleared() { 290 return memKey, memValue, err 291 } 292 293 if memKey != nil { 294 m.currentMemEntry.key = memKey 295 m.currentMemEntry.value = memValue 296 m.currentDbEntry.key, m.currentDbEntry.value, err = m.cursor.Seek(seek) 297 m.isPrevFromDb = false 298 m.currentPair = cursorEntry{memKey, memValue} 299 return memKey, memValue, err 300 } 301 302 dbKey, dbValue, err := m.cursor.SeekExact(seek) 303 if err != nil { 304 return nil, nil, err 305 } 306 307 if dbKey != nil && !m.mutation.isEntryDeleted(m.table, seek) { 308 m.currentDbEntry.key = dbKey 309 m.currentDbEntry.value = dbValue 310 m.currentMemEntry.key, m.currentMemEntry.value, err = m.memCursor.Seek(seek) 311 m.isPrevFromDb = true 312 m.currentPair = cursorEntry{dbKey, dbValue} 313 return dbKey, dbValue, err 314 } 315 return nil, nil, nil 316 } 317 318 func (m *memoryMutationCursor) Put(k, v []byte) error { 319 return m.mutation.Put(m.table, common.Copy(k), common.Copy(v)) 320 } 321 322 func (m *memoryMutationCursor) Append(k []byte, v []byte) error { 323 return m.mutation.Append(m.table, common.Copy(k), common.Copy(v)) 324 325 } 326 327 func (m *memoryMutationCursor) AppendDup(k []byte, v []byte) error { 328 return m.memCursor.AppendDup(common.Copy(k), common.Copy(v)) 329 } 330 331 func (m *memoryMutationCursor) PutNoDupData(key, value []byte) error { 332 panic("Not implemented") 333 } 334 335 func (m *memoryMutationCursor) Delete(k []byte) error { 336 return m.mutation.Delete(m.table, k) 337 } 338 339 func (m *memoryMutationCursor) DeleteCurrent() error { 340 panic("DeleteCurrent Not implemented") 341 } 342 func (m *memoryMutationCursor) DeleteExact(_, _ []byte) error { 343 panic("DeleteExact Not implemented") 344 } 345 346 func (m *memoryMutationCursor) DeleteCurrentDuplicates() error { 347 config, ok := kv.ChaindataTablesCfg[m.table] 348 autoKeyConversion := ok && config.AutoDupSortKeysConversion 349 if autoKeyConversion { 350 panic("DeleteCurrentDuplicates Not implemented for AutoDupSortKeysConversion tables") 351 } 352 353 k, _, err := m.Current() 354 if err != nil { 355 return err 356 } 357 if k != nil { 358 return m.Delete(k) 359 } 360 return nil 361 } 362 363 // Seek move pointer to a key at a certain position. 364 func (m *memoryMutationCursor) SeekBothRange(key, value []byte) ([]byte, error) { 365 if m.isTableCleared() { 366 return m.memCursor.SeekBothRange(key, value) 367 } 368 369 dbValue, err := m.cursor.SeekBothRange(key, value) 370 if err != nil { 371 return nil, err 372 } 373 374 if dbValue != nil && m.isEntryDeleted(key, dbValue, Dup) { 375 _, dbValue, err = m.getNextOnDb(Dup) 376 if err != nil { 377 return nil, err 378 } 379 } 380 381 memValue, err := m.memCursor.SeekBothRange(key, value) 382 if err != nil { 383 return nil, err 384 } 385 _, retValue, err := m.resolveCursorPriority(key, memValue, key, dbValue, Dup) 386 return retValue, err 387 } 388 389 func (m *memoryMutationCursor) Last() ([]byte, []byte, error) { 390 memKey, memValue, err := m.memCursor.Last() 391 if err != nil || m.isTableCleared() { 392 return memKey, memValue, err 393 } 394 395 dbKey, dbValue, err := m.cursor.Last() 396 if err != nil { 397 return nil, nil, err 398 } 399 400 dbKey, dbValue, err = m.skipIntersection(memKey, memValue, dbKey, dbValue, Normal) 401 if err != nil { 402 return nil, nil, err 403 } 404 405 m.currentDbEntry = cursorEntry{dbKey, dbValue} 406 m.currentMemEntry = cursorEntry{memKey, memValue} 407 408 // Basic checks 409 if dbKey != nil && m.isEntryDeleted(dbKey, dbValue, Normal) { 410 m.currentDbEntry = cursorEntry{} 411 m.isPrevFromDb = false 412 return memKey, memValue, nil 413 } 414 415 if dbValue == nil { 416 m.isPrevFromDb = false 417 return memKey, memValue, nil 418 } 419 420 if memValue == nil { 421 m.isPrevFromDb = true 422 return dbKey, dbValue, nil 423 } 424 // Check which one is last and return it 425 keyCompare := bytes.Compare(memKey, dbKey) 426 if keyCompare == 0 { 427 if bytes.Compare(memValue, dbValue) > 0 { 428 m.currentDbEntry = cursorEntry{} 429 m.isPrevFromDb = false 430 return memKey, memValue, nil 431 } 432 m.currentMemEntry = cursorEntry{} 433 m.isPrevFromDb = true 434 return dbKey, dbValue, nil 435 } 436 437 if keyCompare > 0 { 438 m.currentDbEntry = cursorEntry{} 439 m.isPrevFromDb = false 440 return memKey, memValue, nil 441 } 442 443 m.currentMemEntry = cursorEntry{} 444 m.isPrevFromDb = true 445 return dbKey, dbValue, nil 446 } 447 448 func (m *memoryMutationCursor) Prev() ([]byte, []byte, error) { 449 panic("Prev is not implemented!") 450 } 451 func (m *memoryMutationCursor) PrevDup() ([]byte, []byte, error) { 452 panic("Prev is not implemented!") 453 } 454 func (m *memoryMutationCursor) PrevNoDup() ([]byte, []byte, error) { 455 panic("Prev is not implemented!") 456 } 457 458 func (m *memoryMutationCursor) Close() { 459 if m.cursor != nil { 460 m.cursor.Close() 461 } 462 if m.memCursor != nil { 463 m.memCursor.Close() 464 } 465 } 466 467 func (m *memoryMutationCursor) Count() (uint64, error) { 468 panic("Not implemented") 469 } 470 471 func (m *memoryMutationCursor) FirstDup() ([]byte, error) { 472 panic("Not implemented") 473 } 474 475 func (m *memoryMutationCursor) NextNoDup() ([]byte, []byte, error) { 476 if m.isTableCleared() { 477 return m.memCursor.NextNoDup() 478 } 479 480 if m.isPrevFromDb { 481 k, v, err := m.getNextOnDb(NoDup) 482 if err != nil { 483 return nil, nil, err 484 } 485 return m.resolveCursorPriority(m.currentMemEntry.key, m.currentMemEntry.value, k, v, NoDup) 486 } 487 488 memK, memV, err := m.memCursor.NextNoDup() 489 if err != nil { 490 return nil, nil, err 491 } 492 493 return m.resolveCursorPriority(memK, memV, m.currentDbEntry.key, m.currentDbEntry.value, NoDup) 494 } 495 496 func (m *memoryMutationCursor) LastDup() ([]byte, error) { 497 panic("Not implemented") 498 } 499 500 func (m *memoryMutationCursor) CountDuplicates() (uint64, error) { 501 panic("Not implemented") 502 } 503 504 func (m *memoryMutationCursor) SeekBothExact(key, value []byte) ([]byte, []byte, error) { 505 panic("SeekBothExact Not implemented") 506 }