ethdb: removed DeleteRange support on batches

This commit is contained in:
Zsolt Felfoldi 2024-10-24 15:43:10 +02:00
parent 5660e57a41
commit f596f79f61
7 changed files with 74 additions and 133 deletions

View file

@ -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.

View file

@ -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
}

View file

@ -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)
})
}

View file

@ -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()
}

View file

@ -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.

View file

@ -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.

View file

@ -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.