Skip to content

Commit 736208b

Browse files
committed
Fix edge case for iterate tombstoned value
1 parent 22bf439 commit 736208b

File tree

3 files changed

+60
-9
lines changed

3 files changed

+60
-9
lines changed

ss/pebbledb/iterator.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ func newPebbleDBIterator(src *pebble.Iterator, prefix, mvccStart, mvccEnd []byte
6363
if valid {
6464
currKey, currKeyVersion, ok := SplitMVCCKey(itr.source.Key())
6565
if !ok {
66-
// XXX: This should not happen as that would indicate we have a malformed
67-
// MVCC value.
68-
panic(fmt.Sprintf("invalid PebbleDB MVCC value: %s", itr.source.Key()))
66+
// XXX: This should not happen as that would indicate we have a malformed MVCC key.
67+
panic(fmt.Sprintf("invalid PebbleDB MVCC key: %s", itr.source.Key()))
6968
}
7069

7170
curKeyVersionDecoded, err := decodeUint64Ascending(currKeyVersion)
@@ -86,6 +85,11 @@ func newPebbleDBIterator(src *pebble.Iterator, prefix, mvccStart, mvccEnd []byte
8685
}
8786
}
8887

88+
// Make sure we do not return any tombstone value
89+
if valTombstoned(itr.source.Value()) {
90+
itr.valid = false
91+
}
92+
8993
return itr
9094
}
9195

ss/test/storage_test_suite.go

+37-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package sstest
22

33
import (
4+
"fmt"
45
"sync"
56

67
"github.com/cosmos/iavl"
8+
"github.com/sei-protocol/sei-db/ss/types"
79
"github.com/stretchr/testify/suite"
810
"golang.org/x/exp/slices"
9-
10-
"fmt"
11-
12-
"github.com/sei-protocol/sei-db/ss/types"
1311
)
1412

1513
const (
@@ -305,7 +303,7 @@ func (s *StorageTestSuite) TestDatabaseIterator() {
305303
s.Require().False(itr.Valid())
306304
}
307305

308-
// iterator with with a start and end domain over multiple versions
306+
// iterator with a start and end domain over multiple versions
309307
for v := int64(1); v < 5; v++ {
310308
itr2, err := db.Iterator(storeKey1, v, []byte("key010"), []byte("key019"))
311309
s.Require().NoError(err)
@@ -333,7 +331,6 @@ func (s *StorageTestSuite) TestDatabaseIterator() {
333331
s.Require().Error(err)
334332
s.Require().Nil(iter3)
335333
}
336-
337334
func (s *StorageTestSuite) TestDatabaseIteratorRangedDeletes() {
338335
db, err := s.NewDB(s.T().TempDir())
339336
s.Require().NoError(err)
@@ -359,6 +356,40 @@ func (s *StorageTestSuite) TestDatabaseIteratorRangedDeletes() {
359356
s.Require().NoError(itr.Error())
360357
}
361358

359+
func (s *StorageTestSuite) TestDatabaseIteratorDeletes() {
360+
db, err := s.NewDB(s.T().TempDir())
361+
s.Require().NoError(err)
362+
defer db.Close()
363+
364+
s.Require().NoError(DBApplyChangeset(db, 1, storeKey1, [][]byte{[]byte("key001")}, [][]byte{[]byte("value001")}))
365+
s.Require().NoError(DBApplyDeleteChangeset(db, 5, storeKey1, [][]byte{[]byte("key001")}))
366+
367+
itr, err := db.Iterator(storeKey1, 11, []byte("key001"), nil)
368+
369+
// there should be no valid key in the iterator
370+
var count = 0
371+
for ; itr.Valid(); itr.Next() {
372+
count++
373+
}
374+
s.Require().Equal(0, count)
375+
s.Require().NoError(itr.Error())
376+
itr.Close()
377+
378+
s.Require().NoError(DBApplyChangeset(db, 10, storeKey1, [][]byte{[]byte("key001")}, [][]byte{[]byte("value002")}))
379+
itr, err = db.Iterator(storeKey1, 11, []byte("key001"), nil)
380+
s.Require().NoError(err)
381+
382+
// there should only be one valid key in the iterator
383+
count = 0
384+
for ; itr.Valid(); itr.Next() {
385+
s.Require().Equal([]byte("key001"), itr.Key())
386+
count++
387+
}
388+
s.Require().Equal(1, count)
389+
s.Require().NoError(itr.Error())
390+
itr.Close()
391+
}
392+
362393
func (s *StorageTestSuite) TestDatabaseIteratorMultiVersion() {
363394
db, err := s.NewDB(s.T().TempDir())
364395
s.Require().NoError(err)

ss/test/utils.go

+16
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,19 @@ func DBApplyChangeset(db types.StateStore, version int64, storeKey string, key,
5959

6060
return db.ApplyChangeset(version, ncs)
6161
}
62+
63+
// Helper for creating the changeset and applying it to db
64+
func DBApplyDeleteChangeset(db types.StateStore, version int64, storeKey string, key [][]byte) error {
65+
cs := &iavl.ChangeSet{}
66+
cs.Pairs = []*iavl.KVPair{}
67+
for j := 0; j < len(key); j++ {
68+
cs.Pairs = append(cs.Pairs, &iavl.KVPair{Key: key[j], Delete: true})
69+
}
70+
71+
ncs := &proto.NamedChangeSet{
72+
Name: storeKey,
73+
Changeset: *cs,
74+
}
75+
76+
return db.ApplyChangeset(version, ncs)
77+
}

0 commit comments

Comments
 (0)