From f596f79f61a6d5281ae4436024cbfcf6a0891e11 Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Thu, 24 Oct 2024 15:43:10 +0200 Subject: [PATCH] ethdb: removed DeleteRange support on batches --- core/rawdb/table.go | 8 +-- ethdb/database.go | 3 +- ethdb/dbtest/testsuite.go | 129 ++++++++++++++----------------------- ethdb/delete_range.go | 39 ++--------- ethdb/leveldb/leveldb.go | 8 +-- ethdb/memorydb/memorydb.go | 8 +-- ethdb/pebble/pebble.go | 12 ++-- 7 files changed, 74 insertions(+), 133 deletions(-) diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 47bd6ca8ab..705d842eab 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -129,7 +129,8 @@ func (t *table) Delete(key []byte) error { return t.db.Delete(append([]byte(t.prefix), key...)) } -// DeleteRange removes all keys in the range [start,end) from the database. +// DeleteRange deletes all of the keys (and values) in the range [start,end) +// (inclusive on start, exclusive on end). func (t *table) DeleteRange(start, end []byte) error { return t.db.DeleteRange(append([]byte(t.prefix), start...), append([]byte(t.prefix), end...)) } @@ -216,10 +217,9 @@ func (b *tableBatch) Delete(key []byte) error { return b.batch.Delete(append([]byte(b.prefix), key...)) } -// DeleteRange inserts the removal all of the keys in the range [start,end) into -// the batch for later committing. +// DeleteRange implements KeyValueWriter (not supported on batches). func (b *tableBatch) DeleteRange(start, end []byte) error { - return b.batch.DeleteRange(append([]byte(b.prefix), start...), append([]byte(b.prefix), end...)) + panic("DeleteRange is not supported on batches") } // ValueSize retrieves the amount of data queued up for writing. diff --git a/ethdb/database.go b/ethdb/database.go index cf5df79c67..0c7ea60cb6 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -36,7 +36,8 @@ type KeyValueWriter interface { // Delete removes the key from the key-value data store. Delete(key []byte) error - // DeleteRange removes all keys in the range [start,end) from the key-value store. + // DeleteRange deletes all of the keys (and values) in the range [start,end) + // (inclusive on start, exclusive on end). DeleteRange(start, end []byte) error } diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 8f3a896e9e..52e6b287cf 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -349,89 +349,58 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { db := New() defer db.Close() - test := func(addToBatch, deleteFromBatch bool) { - var batch ethdb.Batch - addRange := func(start, stop int) { - if addToBatch { - batch = db.NewBatch() - } - for i := start; i <= stop; i++ { - if addToBatch { - batch.Put([]byte(strconv.Itoa(i)), nil) - } else { - db.Put([]byte(strconv.Itoa(i)), nil) - } - } - if addToBatch && !deleteFromBatch { - batch.Write() - batch = nil - } + addRange := func(start, stop int) { + for i := start; i <= stop; i++ { + db.Put([]byte(strconv.Itoa(i)), nil) } - - deleteRange := func(start, end []byte) { - if deleteFromBatch { - if batch == nil { - batch = db.NewBatch() - } - batch.DeleteRange(start, end) - batch.Write() - batch = nil - } else { - db.DeleteRange(start, end) - } - } - - checkRange := func(start, stop int, exp bool) { - for i := start; i <= stop; i++ { - has, _ := db.Has([]byte(strconv.Itoa(i))) - if has && !exp { - t.Fatalf("unexpected key %d", i) - } - if !has && exp { - t.Fatalf("missing expected key %d", i) - } - } - } - - addRange(1, 9) - deleteRange([]byte("9"), []byte("1")) - checkRange(1, 9, true) - deleteRange([]byte("5"), []byte("5")) - checkRange(1, 9, true) - deleteRange([]byte("5"), []byte("50")) - checkRange(1, 4, true) - checkRange(5, 5, false) - checkRange(6, 9, true) - deleteRange([]byte(""), []byte("a")) - checkRange(1, 9, false) - - addRange(1, 999) - deleteRange([]byte("12345"), []byte("54321")) - checkRange(1, 1, true) - checkRange(2, 5, false) - checkRange(6, 12, true) - checkRange(13, 54, false) - checkRange(55, 123, true) - checkRange(124, 543, false) - checkRange(544, 999, true) - - addRange(1, 999) - deleteRange([]byte("3"), []byte("7")) - checkRange(1, 2, true) - checkRange(3, 6, false) - checkRange(7, 29, true) - checkRange(30, 69, false) - checkRange(70, 299, true) - checkRange(300, 699, false) - checkRange(700, 999, true) - - deleteRange([]byte(""), []byte("a")) - checkRange(1, 999, false) } - test(false, false) - test(false, true) - test(true, true) + checkRange := func(start, stop int, exp bool) { + for i := start; i <= stop; i++ { + has, _ := db.Has([]byte(strconv.Itoa(i))) + if has && !exp { + t.Fatalf("unexpected key %d", i) + } + if !has && exp { + t.Fatalf("missing expected key %d", i) + } + } + } + + addRange(1, 9) + db.DeleteRange([]byte("9"), []byte("1")) + checkRange(1, 9, true) + db.DeleteRange([]byte("5"), []byte("5")) + checkRange(1, 9, true) + db.DeleteRange([]byte("5"), []byte("50")) + checkRange(1, 4, true) + checkRange(5, 5, false) + checkRange(6, 9, true) + db.DeleteRange([]byte(""), []byte("a")) + checkRange(1, 9, false) + + addRange(1, 999) + db.DeleteRange([]byte("12345"), []byte("54321")) + checkRange(1, 1, true) + checkRange(2, 5, false) + checkRange(6, 12, true) + checkRange(13, 54, false) + checkRange(55, 123, true) + checkRange(124, 543, false) + checkRange(544, 999, true) + + addRange(1, 999) + db.DeleteRange([]byte("3"), []byte("7")) + checkRange(1, 2, true) + checkRange(3, 6, false) + checkRange(7, 29, true) + checkRange(30, 69, false) + checkRange(70, 299, true) + checkRange(300, 699, false) + checkRange(700, 999, true) + + db.DeleteRange([]byte(""), []byte("a")) + checkRange(1, 999, false) }) } diff --git a/ethdb/delete_range.go b/ethdb/delete_range.go index dad5d2f8ef..b74cc3d39c 100644 --- a/ethdb/delete_range.go +++ b/ethdb/delete_range.go @@ -32,46 +32,21 @@ var ErrTooManyKeys = errors.New("too many keys in deleted range") // finally succeeds. func DeleteRangeWithIterator(db KeyValueStore, start, end []byte) error { batch := db.NewBatch() - if err := deleteRangeWithIterator(batch, db, start, end); err != nil { - return err - } - return batch.Write() -} + it := db.NewIterator(nil, start) + defer it.Release() -// DeleteRangeFromBatch is a fallback method for deleting a key range in a batch -// from a database that does not natively support range deletion. -func DeleteRangeFromBatch(target Batch, source Iteratee, start, end []byte) error { - deleteRangeWithIterator(target, source, start, end) - var keys [][]byte - writer := HookedBatch{ - Batch: target, - OnPut: func(key []byte, value []byte) { - if bytes.Compare(start, key) <= 0 && bytes.Compare(end, key) > 0 { - keys = append(keys, key) - } - }, - } - target.Replay(writer) - for _, key := range keys { - if err := target.Delete(key); err != nil { - return err - } - } - return nil -} - -func deleteRangeWithIterator(target KeyValueWriter, source Iteratee, start, end []byte) error { - it := source.NewIterator(nil, start) var count int for it.Next() && bytes.Compare(end, it.Key()) > 0 { count++ if count > 10000 { // should not block for more than a second + if err := batch.Write(); err != nil { + return err + } return ErrTooManyKeys } - if err := target.Delete(it.Key()); err != nil { + if err := batch.Delete(it.Key()); err != nil { return err } } - it.Release() - return nil + return batch.Write() } diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 19840e21b3..bc29f95de5 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -206,7 +206,8 @@ func (db *Database) Delete(key []byte) error { return db.db.Delete(key, nil) } -// DeleteRange removes all keys in the range [start,end) from the key-value store. +// DeleteRange deletes all of the keys (and values) in the range [start,end) +// (inclusive on start, exclusive on end). func (db *Database) DeleteRange(start, end []byte) error { return ethdb.DeleteRangeWithIterator(db, start, end) } @@ -440,10 +441,9 @@ func (b *batch) Delete(key []byte) error { return nil } -// DeleteRange inserts the removal all of the keys in the range [start,end) into -// the batch for later committing. +// DeleteRange implements KeyValueWriter (not supported on batches). func (b *batch) DeleteRange(start, end []byte) error { - return ethdb.DeleteRangeFromBatch(b, b.wrappedDb, start, end) + panic("DeleteRange is not supported on batches") } // ValueSize retrieves the amount of data queued up for writing. diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 64f7fcd4ba..369cd28bad 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -121,7 +121,8 @@ func (db *Database) Delete(key []byte) error { return nil } -// DeleteRange removes all keys in the range [start,end) from the key-value store. +// DeleteRange deletes all of the keys (and values) in the range [start,end) +// (inclusive on start, exclusive on end). func (db *Database) DeleteRange(start, end []byte) error { return ethdb.DeleteRangeWithIterator(db, start, end) } @@ -228,10 +229,9 @@ func (b *batch) Delete(key []byte) error { return nil } -// DeleteRange inserts the removal all of the keys in the range [start,end) into -// the batch for later committing. +// DeleteRange implements KeyValueWriter (not supported on batches). func (b *batch) DeleteRange(start, end []byte) error { - return ethdb.DeleteRangeFromBatch(b, b.db, start, end) + panic("DeleteRange is not supported on batches") } // ValueSize retrieves the amount of data queued up for writing. diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 2e45628267..c20c402f3a 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -338,7 +338,8 @@ func (d *Database) Delete(key []byte) error { return d.db.Delete(key, nil) } -// DeleteRange removes all keys in the range [start,end) from the key-value store. +// DeleteRange deletes all of the keys (and values) in the range [start,end) +// (inclusive on start, exclusive on end). func (d *Database) DeleteRange(start, end []byte) error { d.quitLock.RLock() defer d.quitLock.RUnlock() @@ -549,14 +550,9 @@ func (b *batch) Delete(key []byte) error { return nil } -// DeleteRange inserts the removal all of the keys in the range [start,end) into -// the batch for later committing. +// DeleteRange implements KeyValueWriter (not supported on batches). func (b *batch) DeleteRange(start, end []byte) error { - if err := b.b.DeleteRange(start, end, nil); err != nil { - return err - } - b.size += len(start) + len(end) - return nil + panic("DeleteRange is not supported on batches") } // ValueSize retrieves the amount of data queued up for writing.