ethdb: moved DeleteRangeWithIterator logic to leveldb/memorydb

This commit is contained in:
Zsolt Felfoldi 2024-10-25 13:49:02 +02:00
parent c1f1ade52e
commit fa8b4504d2
5 changed files with 54 additions and 75 deletions

View file

@ -1,52 +0,0 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package ethdb defines the interfaces for an Ethereum data store.
package ethdb
import (
"bytes"
"errors"
)
var ErrTooManyKeys = errors.New("too many keys in deleted range")
// DeleteRangeWithIterator is a fallback method for deleting a key range from a
// database that does not natively support range deletion.
// Note that the number of deleted keys is limited in order to avoid blocking for
// a very long time. ErrTooManyKeys is returned if the range has only been
// partially deleted. In this case the caller can repeat the call until it
// finally succeeds.
func DeleteRangeWithIterator(db KeyValueStore, start, end []byte) error {
batch := db.NewBatch()
it := db.NewIterator(nil, start)
defer it.Release()
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 := batch.Delete(it.Key()); err != nil {
return err
}
}
return batch.Write()
}

View file

@ -21,6 +21,7 @@
package leveldb
import (
"bytes"
"fmt"
"sync"
"time"
@ -206,10 +207,34 @@ func (db *Database) Delete(key []byte) error {
return db.db.Delete(key, nil)
}
var ErrTooManyKeys = errors.New("too many keys in deleted range")
// DeleteRange deletes all of the keys (and values) in the range [start,end)
// (inclusive on start, exclusive on end).
// Note that this is a fallback implementation as leveldb does not natively
// support range deletion. It can be slow and therefore the number of deleted
// keys is limited in order to avoid blocking for a very long time.
// ErrTooManyKeys is returned if the range has only been partially deleted.
// In this case the caller can repeat the call until it finally succeeds.
func (db *Database) DeleteRange(start, end []byte) error {
return ethdb.DeleteRangeWithIterator(db, start, end)
batch := db.NewBatch()
it := db.NewIterator(nil, start)
defer it.Release()
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 := batch.Delete(it.Key()); err != nil {
return err
}
}
return batch.Write()
}
// NewBatch creates a write-only key-value store that buffers changes to its host
@ -217,7 +242,6 @@ func (db *Database) DeleteRange(start, end []byte) error {
func (db *Database) NewBatch() ethdb.Batch {
return &batch{
db: db.db,
wrappedDb: db,
b: new(leveldb.Batch),
}
}
@ -226,7 +250,6 @@ func (db *Database) NewBatch() ethdb.Batch {
func (db *Database) NewBatchWithSize(size int) ethdb.Batch {
return &batch{
db: db.db,
wrappedDb: db,
b: leveldb.MakeBatch(size),
}
}
@ -422,7 +445,6 @@ func (db *Database) meter(refresh time.Duration, namespace string) {
// when Write is called. A batch cannot be used concurrently.
type batch struct {
db *leveldb.DB
wrappedDb *Database
b *leveldb.Batch
size int
}

View file

@ -18,6 +18,7 @@
package memorydb
import (
"bytes"
"errors"
"sort"
"strings"
@ -124,7 +125,15 @@ func (db *Database) Delete(key []byte) error {
// 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)
it := db.NewIterator(nil, start)
defer it.Release()
for it.Next() && bytes.Compare(end, it.Key()) > 0 {
if err := db.Delete(it.Key()); err != nil {
return err
}
}
return nil
}
// NewBatch creates a write-only key-value store that buffers changes to its host

View file

@ -335,7 +335,7 @@ func (d *Database) Delete(key []byte) error {
if d.closed {
return pebble.ErrClosed
}
return d.db.Delete(key, nil)
return d.db.Delete(key, d.writeOptions)
}
// DeleteRange deletes all of the keys (and values) in the range [start,end)
@ -346,7 +346,7 @@ func (d *Database) DeleteRange(start, end []byte) error {
if d.closed {
return pebble.ErrClosed
}
return d.db.DeleteRange(start, end, nil)
return d.db.DeleteRange(start, end, d.writeOptions)
}
// NewBatch creates a write-only key-value store that buffers changes to its host