diff --git a/eth/protocols/snap/gentrie_test.go b/eth/protocols/snap/gentrie_test.go index 193d4eef3d..2da4f3c866 100644 --- a/eth/protocols/snap/gentrie_test.go +++ b/eth/protocols/snap/gentrie_test.go @@ -241,7 +241,7 @@ func TestPartialGentree(t *testing.T) { {2, len(entries) - 2}, // no left and right {2, len(entries) - 2}, // no left and right {len(entries) / 2, len(entries) / 2}, // single - {0, 0}, // single first + {0, 0}, // single first {len(entries) - 1, len(entries) - 1}, // single last } for _, c := range cases { @@ -350,7 +350,7 @@ func TestGentreeDanglingClearing(t *testing.T) { {2, len(entries) - 2}, // no left and right {2, len(entries) - 2}, // no left and right {len(entries) / 2, len(entries) / 2}, // single - {0, 0}, // single first + {0, 0}, // single first {len(entries) - 1, len(entries) - 1}, // single last } for _, c := range cases { @@ -390,13 +390,13 @@ func TestFlushPartialTree(t *testing.T) { first int last int }{ - {0, len(entries) - 1}, // full - {1, len(entries) - 1}, // no left - {10, len(entries) - 1}, // no left - {10, len(entries) - 2}, // no left and right - {10, len(entries) - 10}, // no left and right - {11, 11}, // single - {0, 0}, // single first + {0, len(entries) - 1}, // full + {1, len(entries) - 1}, // no left + {10, len(entries) - 1}, // no left + {10, len(entries) - 2}, // no left and right + {10, len(entries) - 10}, // no left and right + {11, 11}, // single + {0, 0}, // single first {len(entries) - 1, len(entries) - 1}, // single last } for _, c := range cases { diff --git a/ethdb/delete_range.go b/ethdb/delete_range.go deleted file mode 100644 index b74cc3d39c..0000000000 --- a/ethdb/delete_range.go +++ /dev/null @@ -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 . - -// 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() -} diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 7bd45287c3..ce7d823561 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -21,6 +21,7 @@ package leveldb import ( + "bytes" "fmt" "sync" "time" @@ -206,28 +207,50 @@ 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 // database until a final write is called. func (db *Database) NewBatch() ethdb.Batch { return &batch{ - db: db.db, - wrappedDb: db, - b: new(leveldb.Batch), + db: db.db, + b: new(leveldb.Batch), } } // NewBatchWithSize creates a write-only database batch with pre-allocated buffer. func (db *Database) NewBatchWithSize(size int) ethdb.Batch { return &batch{ - db: db.db, - wrappedDb: db, - b: leveldb.MakeBatch(size), + db: db.db, + b: leveldb.MakeBatch(size), } } @@ -421,10 +444,9 @@ func (db *Database) meter(refresh time.Duration, namespace string) { // batch is a write-only leveldb batch that commits changes to its host database // when Write is called. A batch cannot be used concurrently. type batch struct { - db *leveldb.DB - wrappedDb *Database - b *leveldb.Batch - size int + db *leveldb.DB + b *leveldb.Batch + size int } // Put inserts the given value into the batch for later committing. diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index b17a4d5410..c6fba39cfd 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -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 diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index a881750441..a9151a3bb5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -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