github.com/ledgerwatch/erigon-lib@v1.0.0/kv/memdb/memory_mutation.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 "context" 19 20 "github.com/ledgerwatch/erigon-lib/common" 21 "github.com/ledgerwatch/erigon-lib/kv/iter" 22 "github.com/ledgerwatch/erigon-lib/kv/order" 23 "github.com/ledgerwatch/log/v3" 24 25 "github.com/ledgerwatch/erigon-lib/kv" 26 "github.com/ledgerwatch/erigon-lib/kv/mdbx" 27 ) 28 29 type MemoryMutation struct { 30 memTx kv.RwTx 31 memDb kv.RwDB 32 deletedEntries map[string]map[string]struct{} 33 clearedTables map[string]struct{} 34 db kv.Tx 35 statelessCursors map[string]kv.RwCursor 36 } 37 38 // NewMemoryBatch - starts in-mem batch 39 // 40 // Common pattern: 41 // 42 // batch := NewMemoryBatch(db, tmpDir) 43 // defer batch.Rollback() 44 // ... some calculations on `batch` 45 // batch.Commit() 46 func NewMemoryBatch(tx kv.Tx, tmpDir string) *MemoryMutation { 47 tmpDB := mdbx.NewMDBX(log.New()).InMem(tmpDir).MustOpen() 48 memTx, err := tmpDB.BeginRw(context.Background()) 49 if err != nil { 50 panic(err) 51 } 52 if err := initSequences(tx, memTx); err != nil { 53 return nil 54 } 55 56 return &MemoryMutation{ 57 db: tx, 58 memDb: tmpDB, 59 memTx: memTx, 60 deletedEntries: make(map[string]map[string]struct{}), 61 clearedTables: make(map[string]struct{}), 62 } 63 } 64 65 func NewMemoryBatchWithCustomDB(tx kv.Tx, db kv.RwDB, uTx kv.RwTx, tmpDir string) *MemoryMutation { 66 return &MemoryMutation{ 67 db: tx, 68 memDb: db, 69 memTx: uTx, 70 deletedEntries: make(map[string]map[string]struct{}), 71 clearedTables: make(map[string]struct{}), 72 } 73 } 74 75 func (m *MemoryMutation) UpdateTxn(tx kv.Tx) { 76 m.db = tx 77 m.statelessCursors = nil 78 } 79 80 func (m *MemoryMutation) isTableCleared(table string) bool { 81 _, ok := m.clearedTables[table] 82 return ok 83 } 84 85 func (m *MemoryMutation) isEntryDeleted(table string, key []byte) bool { 86 _, ok := m.deletedEntries[table] 87 if !ok { 88 return ok 89 } 90 _, ok = m.deletedEntries[table][string(key)] 91 return ok 92 } 93 94 func (m *MemoryMutation) DBSize() (uint64, error) { 95 panic("not implemented") 96 } 97 98 func initSequences(db kv.Tx, memTx kv.RwTx) error { 99 cursor, err := db.Cursor(kv.Sequence) 100 if err != nil { 101 return err 102 } 103 for k, v, err := cursor.First(); k != nil; k, v, err = cursor.Next() { 104 if err != nil { 105 return err 106 } 107 if err := memTx.Put(kv.Sequence, k, v); err != nil { 108 return err 109 } 110 } 111 return nil 112 } 113 114 func (m *MemoryMutation) IncrementSequence(bucket string, amount uint64) (uint64, error) { 115 return m.memTx.IncrementSequence(bucket, amount) 116 } 117 118 func (m *MemoryMutation) ReadSequence(bucket string) (uint64, error) { 119 return m.memTx.ReadSequence(bucket) 120 } 121 122 func (m *MemoryMutation) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error { 123 if amount == 0 { 124 return nil 125 } 126 c, err := m.Cursor(bucket) 127 if err != nil { 128 return err 129 } 130 defer c.Close() 131 132 for k, v, err := c.Seek(prefix); k != nil && amount > 0; k, v, err = c.Next() { 133 if err != nil { 134 return err 135 } 136 if err := walker(k, v); err != nil { 137 return err 138 } 139 amount-- 140 } 141 return nil 142 } 143 144 func (m *MemoryMutation) statelessCursor(table string) (kv.RwCursor, error) { 145 if m.statelessCursors == nil { 146 m.statelessCursors = make(map[string]kv.RwCursor) 147 } 148 c, ok := m.statelessCursors[table] 149 if !ok { 150 var err error 151 c, err = m.RwCursor(table) 152 if err != nil { 153 return nil, err 154 } 155 m.statelessCursors[table] = c 156 } 157 return c, nil 158 } 159 160 // Can only be called from the worker thread 161 func (m *MemoryMutation) GetOne(table string, key []byte) ([]byte, error) { 162 c, err := m.statelessCursor(table) 163 if err != nil { 164 return nil, err 165 } 166 _, v, err := c.SeekExact(key) 167 return v, err 168 } 169 170 func (m *MemoryMutation) Last(table string) ([]byte, []byte, error) { 171 panic("not implemented. (MemoryMutation.Last)") 172 } 173 174 // Has return whether a key is present in a certain table. 175 func (m *MemoryMutation) Has(table string, key []byte) (bool, error) { 176 c, err := m.statelessCursor(table) 177 if err != nil { 178 return false, err 179 } 180 k, _, err := c.Seek(key) 181 if err != nil { 182 return false, err 183 } 184 return bytes.Equal(key, k), nil 185 } 186 187 func (m *MemoryMutation) Put(table string, k, v []byte) error { 188 return m.memTx.Put(table, k, v) 189 } 190 191 func (m *MemoryMutation) Append(table string, key []byte, value []byte) error { 192 return m.memTx.Append(table, key, value) 193 } 194 195 func (m *MemoryMutation) AppendDup(table string, key []byte, value []byte) error { 196 c, err := m.statelessCursor(table) 197 if err != nil { 198 return err 199 } 200 return c.(*memoryMutationCursor).AppendDup(key, value) 201 } 202 203 func (m *MemoryMutation) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error { 204 c, err := m.Cursor(bucket) 205 if err != nil { 206 return err 207 } 208 defer c.Close() 209 210 for k, v, err := c.Seek(fromPrefix); k != nil; k, v, err = c.Next() { 211 if err != nil { 212 return err 213 } 214 if err := walker(k, v); err != nil { 215 return err 216 } 217 } 218 return nil 219 } 220 221 func (m *MemoryMutation) Prefix(table string, prefix []byte) (iter.KV, error) { 222 nextPrefix, ok := kv.NextSubtree(prefix) 223 if !ok { 224 return m.Stream(table, prefix, nil) 225 } 226 return m.Stream(table, prefix, nextPrefix) 227 } 228 func (m *MemoryMutation) Stream(table string, fromPrefix, toPrefix []byte) (iter.KV, error) { 229 panic("please implement me") 230 } 231 func (m *MemoryMutation) StreamAscend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) { 232 panic("please implement me") 233 } 234 func (m *MemoryMutation) StreamDescend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) { 235 panic("please implement me") 236 } 237 func (m *MemoryMutation) Range(table string, fromPrefix, toPrefix []byte) (iter.KV, error) { 238 panic("please implement me") 239 } 240 func (m *MemoryMutation) RangeAscend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) { 241 panic("please implement me") 242 } 243 func (m *MemoryMutation) RangeDescend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) { 244 panic("please implement me") 245 } 246 func (m *MemoryMutation) RangeDupSort(table string, key []byte, fromPrefix, toPrefix []byte, asc order.By, limit int) (iter.KV, error) { 247 panic("please implement me") 248 } 249 250 func (m *MemoryMutation) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error { 251 c, err := m.Cursor(bucket) 252 if err != nil { 253 return err 254 } 255 defer c.Close() 256 257 for k, v, err := c.Seek(prefix); k != nil; k, v, err = c.Next() { 258 if err != nil { 259 return err 260 } 261 if !bytes.HasPrefix(k, prefix) { 262 break 263 } 264 if err := walker(k, v); err != nil { 265 return err 266 } 267 } 268 return nil 269 } 270 271 func (m *MemoryMutation) Delete(table string, k []byte) error { 272 if _, ok := m.deletedEntries[table]; !ok { 273 m.deletedEntries[table] = make(map[string]struct{}) 274 } 275 m.deletedEntries[table][string(k)] = struct{}{} 276 return m.memTx.Delete(table, k) 277 } 278 279 func (m *MemoryMutation) Commit() error { 280 m.statelessCursors = nil 281 return nil 282 } 283 284 func (m *MemoryMutation) Rollback() { 285 m.memTx.Rollback() 286 m.memDb.Close() 287 m.statelessCursors = nil 288 } 289 290 func (m *MemoryMutation) Close() { 291 m.Rollback() 292 } 293 294 func (m *MemoryMutation) BucketSize(bucket string) (uint64, error) { 295 return m.memTx.BucketSize(bucket) 296 } 297 298 func (m *MemoryMutation) DropBucket(bucket string) error { 299 panic("Not implemented") 300 } 301 302 func (m *MemoryMutation) ExistsBucket(bucket string) (bool, error) { 303 panic("Not implemented") 304 } 305 306 func (m *MemoryMutation) ListBuckets() ([]string, error) { 307 panic("Not implemented") 308 } 309 310 func (m *MemoryMutation) ClearBucket(bucket string) error { 311 m.clearedTables[bucket] = struct{}{} 312 return m.memTx.ClearBucket(bucket) 313 } 314 315 func (m *MemoryMutation) CollectMetrics() { 316 } 317 318 func (m *MemoryMutation) CreateBucket(bucket string) error { 319 return m.memTx.CreateBucket(bucket) 320 } 321 322 func (m *MemoryMutation) Flush(tx kv.RwTx) error { 323 // Obtain buckets touched. 324 buckets, err := m.memTx.ListBuckets() 325 if err != nil { 326 return err 327 } 328 // Obliterate buckets who are to be deleted 329 for bucket := range m.clearedTables { 330 if err := tx.ClearBucket(bucket); err != nil { 331 return err 332 } 333 } 334 // Obliterate entries who are to be deleted 335 for bucket, keys := range m.deletedEntries { 336 for key := range keys { 337 if err := tx.Delete(bucket, []byte(key)); err != nil { 338 return err 339 } 340 } 341 } 342 // Iterate over each bucket and apply changes accordingly. 343 for _, bucket := range buckets { 344 if isTablePurelyDupsort(bucket) { 345 cbucket, err := m.memTx.CursorDupSort(bucket) 346 if err != nil { 347 return err 348 } 349 defer cbucket.Close() 350 dbCursor, err := tx.RwCursorDupSort(bucket) 351 if err != nil { 352 return err 353 } 354 defer dbCursor.Close() 355 for k, v, err := cbucket.First(); k != nil; k, v, err = cbucket.Next() { 356 if err != nil { 357 return err 358 } 359 if err := dbCursor.Put(k, v); err != nil { 360 return err 361 } 362 } 363 } else { 364 cbucket, err := m.memTx.Cursor(bucket) 365 if err != nil { 366 return err 367 } 368 defer cbucket.Close() 369 for k, v, err := cbucket.First(); k != nil; k, v, err = cbucket.Next() { 370 if err != nil { 371 return err 372 } 373 if err := tx.Put(bucket, k, v); err != nil { 374 return err 375 } 376 } 377 } 378 } 379 return nil 380 } 381 382 func (m *MemoryMutation) Diff() (*MemoryDiff, error) { 383 memDiff := &MemoryDiff{ 384 diff: make(map[table][]entry), 385 deletedEntries: make(map[string][]string), 386 } 387 // Obtain buckets touched. 388 buckets, err := m.memTx.ListBuckets() 389 if err != nil { 390 return nil, err 391 } 392 // Obliterate buckets who are to be deleted 393 for bucket := range m.clearedTables { 394 memDiff.clearedTableNames = append(memDiff.clearedTableNames, bucket) 395 } 396 // Obliterate entries who are to be deleted 397 for bucket, keys := range m.deletedEntries { 398 for key := range keys { 399 memDiff.deletedEntries[bucket] = append(memDiff.deletedEntries[bucket], key) 400 } 401 } 402 // Iterate over each bucket and apply changes accordingly. 403 for _, bucket := range buckets { 404 if isTablePurelyDupsort(bucket) { 405 cbucket, err := m.memTx.CursorDupSort(bucket) 406 if err != nil { 407 return nil, err 408 } 409 defer cbucket.Close() 410 411 t := table{ 412 name: bucket, 413 dupsort: true, 414 } 415 for k, v, err := cbucket.First(); k != nil; k, v, err = cbucket.Next() { 416 if err != nil { 417 return nil, err 418 } 419 memDiff.diff[t] = append(memDiff.diff[t], entry{ 420 k: common.Copy(k), 421 v: common.Copy(v), 422 }) 423 } 424 } else { 425 cbucket, err := m.memTx.Cursor(bucket) 426 if err != nil { 427 return nil, err 428 } 429 defer cbucket.Close() 430 t := table{ 431 name: bucket, 432 dupsort: false, 433 } 434 for k, v, err := cbucket.First(); k != nil; k, v, err = cbucket.Next() { 435 if err != nil { 436 return nil, err 437 } 438 memDiff.diff[t] = append(memDiff.diff[t], entry{ 439 k: common.Copy(k), 440 v: common.Copy(v), 441 }) 442 } 443 } 444 } 445 return memDiff, nil 446 } 447 448 // Check if a bucket is dupsorted and has dupsort conversion off 449 func isTablePurelyDupsort(bucket string) bool { 450 config, ok := kv.ChaindataTablesCfg[bucket] 451 // If we do not have the configuration we assume it is not dupsorted 452 if !ok { 453 return false 454 } 455 return !config.AutoDupSortKeysConversion && config.Flags == kv.DupSort 456 } 457 458 func (m *MemoryMutation) MemDB() kv.RwDB { 459 return m.memDb 460 } 461 462 func (m *MemoryMutation) MemTx() kv.RwTx { 463 return m.memTx 464 } 465 466 // Cursor creates a new cursor (the real fun begins here) 467 func (m *MemoryMutation) makeCursor(bucket string) (kv.RwCursorDupSort, error) { 468 c := &memoryMutationCursor{} 469 // We can filter duplicates in dup sorted table 470 c.table = bucket 471 472 var err error 473 c.cursor, err = m.db.CursorDupSort(bucket) 474 if err != nil { 475 return nil, err 476 } 477 c.memCursor, err = m.memTx.RwCursorDupSort(bucket) 478 if err != nil { 479 return nil, err 480 } 481 c.mutation = m 482 return c, err 483 } 484 485 // Cursor creates a new cursor (the real fun begins here) 486 func (m *MemoryMutation) RwCursorDupSort(bucket string) (kv.RwCursorDupSort, error) { 487 return m.makeCursor(bucket) 488 } 489 490 // Cursor creates a new cursor (the real fun begins here) 491 func (m *MemoryMutation) RwCursor(bucket string) (kv.RwCursor, error) { 492 return m.makeCursor(bucket) 493 } 494 495 // Cursor creates a new cursor (the real fun begins here) 496 func (m *MemoryMutation) CursorDupSort(bucket string) (kv.CursorDupSort, error) { 497 return m.makeCursor(bucket) 498 } 499 500 // Cursor creates a new cursor (the real fun begins here) 501 func (m *MemoryMutation) Cursor(bucket string) (kv.Cursor, error) { 502 return m.makeCursor(bucket) 503 } 504 505 func (m *MemoryMutation) ViewID() uint64 { 506 panic("ViewID Not implemented") 507 }