mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
ethdb: simlify the range deletion
This commit is contained in:
parent
6f76fec4c5
commit
cabe2dafde
5 changed files with 149 additions and 179 deletions
|
|
@ -46,6 +46,11 @@ var ErrTooManyKeys = errors.New("too many keys in deleted range")
|
||||||
type KeyValueRangeDeleter interface {
|
type KeyValueRangeDeleter interface {
|
||||||
// DeleteRange deletes all of the keys (and values) in the range [start,end)
|
// DeleteRange deletes all of the keys (and values) in the range [start,end)
|
||||||
// (inclusive on start, exclusive on end).
|
// (inclusive on start, exclusive on end).
|
||||||
|
//
|
||||||
|
// A nil start is treated as a key before all keys in the data store; a nil
|
||||||
|
// end is treated as a key after all keys in the data store. If both is nil
|
||||||
|
// then the entire data store will be purged.
|
||||||
|
//
|
||||||
// Some implementations of DeleteRange may return ErrTooManyKeys after
|
// Some implementations of DeleteRange may return ErrTooManyKeys after
|
||||||
// partially deleting entries in the given range.
|
// partially deleting entries in the given range.
|
||||||
DeleteRange(start, end []byte) error
|
DeleteRange(start, end []byte) error
|
||||||
|
|
|
||||||
|
|
@ -401,6 +401,10 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
|
|
||||||
db.DeleteRange([]byte(""), []byte("a"))
|
db.DeleteRange([]byte(""), []byte("a"))
|
||||||
checkRange(1, 999, false)
|
checkRange(1, 999, false)
|
||||||
|
|
||||||
|
addRange(1, 999)
|
||||||
|
db.DeleteRange(nil, nil)
|
||||||
|
checkRange(1, 999, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("BatchDeleteRange", func(t *testing.T) {
|
t.Run("BatchDeleteRange", func(t *testing.T) {
|
||||||
|
|
@ -439,29 +443,35 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
checkKeys(1, 10, true)
|
checkKeys(1, 10, true)
|
||||||
|
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
// DeleteRange(start, end) should delete keys where: start <= key < end
|
|
||||||
if err := batch.DeleteRange([]byte("3"), []byte("8")); err != nil {
|
if err := batch.DeleteRange([]byte("3"), []byte("8")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys shouldn't be deleted until Write is called
|
// Keys shouldn't be deleted until Write is called
|
||||||
checkKeys(1, 10, true)
|
checkKeys(1, 10, true)
|
||||||
|
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// After Write, keys in range should be deleted
|
// After Write, keys in range should be deleted
|
||||||
// Range is [start, end) - inclusive of start, exclusive of end
|
// Range is [start, end) - inclusive of start, exclusive of end
|
||||||
checkKeys(1, 2, true) // These should still exist
|
checkKeys(1, 2, true) // These should still exist
|
||||||
checkKeys(3, 7, false) // These should be deleted (3 to 7 inclusive)
|
checkKeys(3, 7, false) // These should be deleted (3 to 7 inclusive)
|
||||||
checkKeys(8, 10, true) // These should still exist (8 is the end boundary, exclusive)
|
checkKeys(8, 10, true) // These should still exist (8 is the end boundary, exclusive)
|
||||||
|
|
||||||
// Test 2: Mix Put, Delete, and DeleteRange in a batch
|
// Test 2: Delete range with special markers
|
||||||
// Reset database for next test by adding back deleted keys
|
|
||||||
addKeys(3, 7)
|
addKeys(3, 7)
|
||||||
|
batch = db.NewBatch()
|
||||||
|
if err := batch.DeleteRange(nil, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
checkKeys(1, 10, false)
|
||||||
|
|
||||||
// Verify keys are back
|
// Test 3: Mix Put, Delete, and DeleteRange in a batch
|
||||||
|
// Reset database for next test by adding back deleted keys
|
||||||
|
addKeys(1, 10)
|
||||||
checkKeys(1, 10, true)
|
checkKeys(1, 10, true)
|
||||||
|
|
||||||
// Create a new batch with multiple operations
|
// Create a new batch with multiple operations
|
||||||
|
|
@ -475,11 +485,9 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
if err := batch.DeleteRange([]byte("1"), []byte("3")); err != nil {
|
if err := batch.DeleteRange([]byte("1"), []byte("3")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check results after batch operations
|
// Check results after batch operations
|
||||||
// Keys 1-2 should be deleted by DeleteRange
|
// Keys 1-2 should be deleted by DeleteRange
|
||||||
checkKeys(1, 2, false)
|
checkKeys(1, 2, false)
|
||||||
|
|
@ -511,7 +519,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
t.Fatalf("key 9 should be deleted")
|
t.Fatalf("key 9 should be deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 3: Reset batch
|
// Test 4: Reset batch
|
||||||
batch.Reset()
|
batch.Reset()
|
||||||
// Individual deletes work better with both string and numeric comparisons
|
// Individual deletes work better with both string and numeric comparisons
|
||||||
if err := batch.Delete([]byte("8")); err != nil {
|
if err := batch.Delete([]byte("8")); err != nil {
|
||||||
|
|
@ -548,7 +556,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
t.Fatalf("key 10 should be deleted")
|
t.Fatalf("key 10 should be deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 4: Empty range
|
// Test 5: Empty range
|
||||||
batch = db.NewBatch()
|
batch = db.NewBatch()
|
||||||
if err := batch.DeleteRange([]byte("100"), []byte("100")); err != nil {
|
if err := batch.DeleteRange([]byte("100"), []byte("100")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -559,7 +567,7 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
// No existing keys should be affected
|
// No existing keys should be affected
|
||||||
checkKeys(3, 7, true)
|
checkKeys(3, 7, true)
|
||||||
|
|
||||||
// Test 5: Test entire keyspace deletion
|
// Test 6: Test entire keyspace deletion
|
||||||
// First clear any existing keys
|
// First clear any existing keys
|
||||||
for i := 1; i <= 100; i++ {
|
for i := 1; i <= 100; i++ {
|
||||||
db.Delete([]byte(strconv.Itoa(i)))
|
db.Delete([]byte(strconv.Itoa(i)))
|
||||||
|
|
@ -580,6 +588,21 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
|
||||||
}
|
}
|
||||||
// All keys should be deleted
|
// All keys should be deleted
|
||||||
checkKeys(50, 60, false)
|
checkKeys(50, 60, false)
|
||||||
|
|
||||||
|
// Test 7: overlapping range deletion
|
||||||
|
addKeys(50, 60)
|
||||||
|
batch = db.NewBatch()
|
||||||
|
if err := batch.DeleteRange([]byte("50"), []byte("55")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := batch.DeleteRange([]byte("52"), []byte("58")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
checkKeys(50, 57, false)
|
||||||
|
checkKeys(58, 60, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("BatchReplayWithDeleteRange", func(t *testing.T) {
|
t.Run("BatchReplayWithDeleteRange", func(t *testing.T) {
|
||||||
|
|
@ -852,7 +875,7 @@ func BenchDatabaseSuite(b *testing.B, New func() ethdb.KeyValueStore) {
|
||||||
|
|
||||||
// Delete some individual keys
|
// Delete some individual keys
|
||||||
for i := 0; i < count/20; i++ {
|
for i := 0; i < count/20; i++ {
|
||||||
batch.Delete([]byte(strconv.Itoa(i*2)))
|
batch.Delete([]byte(strconv.Itoa(i * 2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete range of keys
|
// Delete range of keys
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ func (db *Database) DeleteRange(start, end []byte) error {
|
||||||
defer it.Release()
|
defer it.Release()
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
for it.Next() && bytes.Compare(end, it.Key()) > 0 {
|
for it.Next() && (end == nil || bytes.Compare(end, it.Key()) > 0) {
|
||||||
count++
|
count++
|
||||||
if count > 10000 { // should not block for more than a second
|
if count > 10000 { // should not block for more than a second
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
|
|
@ -461,48 +461,19 @@ func (b *batch) Delete(key []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRange removes all keys in the range [start, end) from the batch for later committing.
|
// DeleteRange removes all keys in the range [start, end) from the batch for
|
||||||
|
// later committing, inclusive on start, exclusive on end.
|
||||||
|
//
|
||||||
// Note that this is a fallback implementation as leveldb does not natively
|
// Note that this is a fallback implementation as leveldb does not natively
|
||||||
// support range deletion in batches. It iterates through the database to find
|
// support range deletion in batches. It iterates through the database to find
|
||||||
// keys in the range and adds them to the batch for deletion.
|
// keys in the range and adds them to the batch for deletion.
|
||||||
func (b *batch) DeleteRange(start, end []byte) error {
|
func (b *batch) DeleteRange(start, end []byte) error {
|
||||||
// Special case: empty range
|
|
||||||
if len(start) == 0 && len(end) == 0 || bytes.Equal(start, end) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case: delete all keys less than end
|
|
||||||
if len(start) == 0 {
|
|
||||||
it := b.db.NewIterator(nil, nil)
|
|
||||||
defer it.Release()
|
|
||||||
|
|
||||||
for it.Next() {
|
|
||||||
key := it.Key()
|
|
||||||
if bytes.Compare(key, end) < 0 {
|
|
||||||
b.b.Delete(key)
|
|
||||||
b.size += len(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return it.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case: delete all keys greater than or equal to start
|
|
||||||
if len(end) == 0 {
|
|
||||||
it := b.db.NewIterator(nil, nil)
|
|
||||||
defer it.Release()
|
|
||||||
|
|
||||||
for it.Next() {
|
|
||||||
key := it.Key()
|
|
||||||
if bytes.Compare(key, start) >= 0 {
|
|
||||||
b.b.Delete(key)
|
|
||||||
b.size += len(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return it.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an iterator to scan through the keys in the range
|
// Create an iterator to scan through the keys in the range
|
||||||
it := b.db.NewIterator(&util.Range{Start: start, Limit: end}, nil)
|
slice := &util.Range{
|
||||||
|
Start: start, // If nil, it represents the key before all keys
|
||||||
|
Limit: end, // If nil, it represents the key after all keys
|
||||||
|
}
|
||||||
|
it := b.db.NewIterator(slice, nil)
|
||||||
defer it.Release()
|
defer it.Release()
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
|
|
@ -516,7 +487,6 @@ func (b *batch) DeleteRange(start, end []byte) error {
|
||||||
b.b.Delete(key)
|
b.b.Delete(key)
|
||||||
b.size += len(key)
|
b.size += len(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := it.Error(); err != nil {
|
if err := it.Error(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -124,47 +123,25 @@ func (db *Database) Delete(key []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRange deletes all of the keys (and values) in the range [start,end)
|
// DeleteRange deletes all of the keys (and values) in the range [start,end)
|
||||||
// (inclusive on start, exclusive on end).
|
// (inclusive on start, exclusive on end). If the start is nil, it represents
|
||||||
|
// the key before all keys; if the end is nil, it represents the key after
|
||||||
|
// all keys.
|
||||||
func (db *Database) DeleteRange(start, end []byte) error {
|
func (db *Database) DeleteRange(start, end []byte) error {
|
||||||
db.lock.Lock()
|
db.lock.Lock()
|
||||||
defer db.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
|
|
||||||
if db.db == nil {
|
if db.db == nil {
|
||||||
return errMemorydbClosed
|
return errMemorydbClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
startStr := string(start)
|
|
||||||
endStr := string(end)
|
|
||||||
|
|
||||||
if startStr == "" && endStr == "" {
|
|
||||||
return nil // Empty range, do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
if startStr == "" {
|
|
||||||
// Delete all keys less than end
|
|
||||||
for key := range db.db {
|
for key := range db.db {
|
||||||
if key < endStr {
|
if start != nil && key < string(start) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if end != nil && key >= string(end) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
delete(db.db, key)
|
delete(db.db, key)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if endStr == "" || endStr > string([]byte{255, 255, 255, 255, 255}) {
|
|
||||||
// Delete all keys greater than or equal to start
|
|
||||||
for key := range db.db {
|
|
||||||
if key >= startStr {
|
|
||||||
delete(db.db, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal case: delete keys in range [start, end)
|
|
||||||
for key := range db.db {
|
|
||||||
if key >= startStr && key < endStr {
|
|
||||||
delete(db.db, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,8 +229,9 @@ type keyvalue struct {
|
||||||
key string
|
key string
|
||||||
value []byte
|
value []byte
|
||||||
delete bool
|
delete bool
|
||||||
rangeFrom string
|
|
||||||
rangeTo string
|
rangeFrom []byte
|
||||||
|
rangeTo []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// batch is a write-only memory batch that commits changes to its host
|
// batch is a write-only memory batch that commits changes to its host
|
||||||
|
|
@ -281,8 +259,8 @@ func (b *batch) Delete(key []byte) error {
|
||||||
// DeleteRange removes all keys in the range [start, end) from the batch for later committing.
|
// DeleteRange removes all keys in the range [start, end) from the batch for later committing.
|
||||||
func (b *batch) DeleteRange(start, end []byte) error {
|
func (b *batch) DeleteRange(start, end []byte) error {
|
||||||
b.writes = append(b.writes, keyvalue{
|
b.writes = append(b.writes, keyvalue{
|
||||||
rangeFrom: string(start),
|
rangeFrom: start,
|
||||||
rangeTo: string(end),
|
rangeTo: end,
|
||||||
delete: true,
|
delete: true,
|
||||||
})
|
})
|
||||||
b.size += len(start) + len(end)
|
b.size += len(start) + len(end)
|
||||||
|
|
@ -302,46 +280,26 @@ func (b *batch) Write() error {
|
||||||
if b.db.db == nil {
|
if b.db.db == nil {
|
||||||
return errMemorydbClosed
|
return errMemorydbClosed
|
||||||
}
|
}
|
||||||
for _, keyvalue := range b.writes {
|
for _, entry := range b.writes {
|
||||||
if keyvalue.delete {
|
if entry.delete {
|
||||||
if keyvalue.key != "" {
|
if entry.key != "" {
|
||||||
// Single key deletion
|
// Single key deletion
|
||||||
delete(b.db.db, keyvalue.key)
|
delete(b.db.db, entry.key)
|
||||||
} else if keyvalue.rangeFrom != "" || keyvalue.rangeTo != "" {
|
|
||||||
// Range deletion (inclusive of start, exclusive of end)
|
|
||||||
// Handle special cases for empty ranges
|
|
||||||
if keyvalue.rangeFrom == keyvalue.rangeTo {
|
|
||||||
// Empty range, do nothing
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if both are numeric strings for consistent comparison
|
|
||||||
startNum, startErr := strconv.Atoi(keyvalue.rangeFrom)
|
|
||||||
endNum, endErr := strconv.Atoi(keyvalue.rangeTo)
|
|
||||||
|
|
||||||
// If both are valid integers, use numeric comparison
|
|
||||||
if startErr == nil && endErr == nil {
|
|
||||||
for key := range b.db.db {
|
|
||||||
if keyNum, err := strconv.Atoi(key); err == nil {
|
|
||||||
if keyNum >= startNum && (keyvalue.rangeTo == "" || keyNum < endNum) {
|
|
||||||
delete(b.db.db, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Use string comparison
|
// Range deletion (inclusive of start, exclusive of end)
|
||||||
for key := range b.db.db {
|
for key := range b.db.db {
|
||||||
// Handle open ranges
|
if entry.rangeFrom != nil && key < string(entry.rangeFrom) {
|
||||||
if (keyvalue.rangeFrom == "" || key >= keyvalue.rangeFrom) &&
|
continue
|
||||||
(keyvalue.rangeTo == "" || key < keyvalue.rangeTo) {
|
}
|
||||||
|
if entry.rangeTo != nil && key >= string(entry.rangeTo) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
delete(b.db.db, key)
|
delete(b.db.db, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.db.db[keyvalue.key] = keyvalue.value
|
b.db.db[entry.key] = entry.value
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -354,17 +312,17 @@ func (b *batch) Reset() {
|
||||||
|
|
||||||
// Replay replays the batch contents.
|
// Replay replays the batch contents.
|
||||||
func (b *batch) Replay(w ethdb.KeyValueWriter) error {
|
func (b *batch) Replay(w ethdb.KeyValueWriter) error {
|
||||||
for _, keyvalue := range b.writes {
|
for _, entry := range b.writes {
|
||||||
if keyvalue.delete {
|
if entry.delete {
|
||||||
if keyvalue.key != "" {
|
if entry.key != "" {
|
||||||
// Single key deletion
|
// Single key deletion
|
||||||
if err := w.Delete([]byte(keyvalue.key)); err != nil {
|
if err := w.Delete([]byte(entry.key)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if keyvalue.rangeFrom != "" || keyvalue.rangeTo != "" {
|
} else {
|
||||||
// Range deletion
|
// Range deletion
|
||||||
if rangeDeleter, ok := w.(ethdb.KeyValueRangeDeleter); ok {
|
if rangeDeleter, ok := w.(ethdb.KeyValueRangeDeleter); ok {
|
||||||
if err := rangeDeleter.DeleteRange([]byte(keyvalue.rangeFrom), []byte(keyvalue.rangeTo)); err != nil {
|
if err := rangeDeleter.DeleteRange(entry.rangeFrom, entry.rangeTo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -373,7 +331,7 @@ func (b *batch) Replay(w ethdb.KeyValueWriter) error {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := w.Put([]byte(keyvalue.key), keyvalue.value); err != nil {
|
if err := w.Put([]byte(entry.key), entry.value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -403,9 +403,16 @@ func (d *Database) Delete(key []byte) error {
|
||||||
func (d *Database) DeleteRange(start, end []byte) error {
|
func (d *Database) DeleteRange(start, end []byte) error {
|
||||||
d.quitLock.RLock()
|
d.quitLock.RLock()
|
||||||
defer d.quitLock.RUnlock()
|
defer d.quitLock.RUnlock()
|
||||||
|
|
||||||
if d.closed {
|
if d.closed {
|
||||||
return pebble.ErrClosed
|
return pebble.ErrClosed
|
||||||
}
|
}
|
||||||
|
// There is no special flag to represent the end of key range
|
||||||
|
// in pebble(nil in leveldb). Use an ugly hack to construct a
|
||||||
|
// large key to represent it.
|
||||||
|
if end == nil {
|
||||||
|
end = bytes.Repeat([]byte{0xff}, 32)
|
||||||
|
}
|
||||||
return d.db.DeleteRange(start, end, d.writeOptions)
|
return d.db.DeleteRange(start, end, d.writeOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -619,8 +626,15 @@ func (b *batch) Delete(key []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRange removes all keys in the range [start, end) from the batch for later committing.
|
// DeleteRange removes all keys in the range [start, end) from the batch for
|
||||||
|
// later committing, inclusive on start, exclusive on end.
|
||||||
func (b *batch) DeleteRange(start, end []byte) error {
|
func (b *batch) DeleteRange(start, end []byte) error {
|
||||||
|
// There is no special flag to represent the end of key range
|
||||||
|
// in pebble(nil in leveldb). Use an ugly hack to construct a
|
||||||
|
// large key to represent it.
|
||||||
|
if end == nil {
|
||||||
|
end = bytes.Repeat([]byte{0xff}, 32)
|
||||||
|
}
|
||||||
if err := b.b.DeleteRange(start, end, nil); err != nil {
|
if err := b.b.DeleteRange(start, end, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue