lib/db: Wrap errors from leveldb iterators (fixes #6263) (#6264)

This commit is contained in:
Simon Frei 2020-01-12 06:06:31 +01:00 committed by Jakob Borg
parent 1b52197f71
commit 08bb730ad0
2 changed files with 34 additions and 2 deletions

View File

@ -14,6 +14,7 @@ import "testing"
func testBackendBehavior(t *testing.T, open func() Backend) { func testBackendBehavior(t *testing.T, open func() Backend) {
t.Run("WriteIsolation", func(t *testing.T) { testWriteIsolation(t, open) }) t.Run("WriteIsolation", func(t *testing.T) { testWriteIsolation(t, open) })
t.Run("DeleteNonexisten", func(t *testing.T) { testDeleteNonexistent(t, open) }) t.Run("DeleteNonexisten", func(t *testing.T) { testDeleteNonexistent(t, open) })
t.Run("IteratorClosedDB", func(t *testing.T) { testIteratorClosedDB(t, open) })
} }
func testWriteIsolation(t *testing.T, open func() Backend) { func testWriteIsolation(t *testing.T, open func() Backend) {
@ -51,3 +52,25 @@ func testDeleteNonexistent(t *testing.T, open func() Backend) {
t.Error(err) t.Error(err)
} }
} }
// Either creating the iterator or the .Error() method of the returned iterator
// should return an error and IsClosed(err) == true.
func testIteratorClosedDB(t *testing.T, open func() Backend) {
db := open()
_ = db.Put([]byte("a"), []byte("a"))
db.Close()
it, err := db.NewPrefixIterator(nil)
if err != nil {
if !IsClosed(err) {
t.Error("NewPrefixIterator: IsClosed(err) == false:", err)
}
return
}
it.Next()
if err := it.Error(); !IsClosed(err) {
t.Error("Next: IsClosed(err) == false:", err)
}
}

View File

@ -10,6 +10,7 @@ import (
"sync" "sync"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/util" "github.com/syndtr/goleveldb/leveldb/util"
) )
@ -65,11 +66,11 @@ func (b *leveldbBackend) Get(key []byte) ([]byte, error) {
} }
func (b *leveldbBackend) NewPrefixIterator(prefix []byte) (Iterator, error) { func (b *leveldbBackend) NewPrefixIterator(prefix []byte) (Iterator, error) {
return b.ldb.NewIterator(util.BytesPrefix(prefix), nil), nil return &leveldbIterator{b.ldb.NewIterator(util.BytesPrefix(prefix), nil)}, nil
} }
func (b *leveldbBackend) NewRangeIterator(first, last []byte) (Iterator, error) { func (b *leveldbBackend) NewRangeIterator(first, last []byte) (Iterator, error) {
return b.ldb.NewIterator(&util.Range{Start: first, Limit: last}, nil), nil return &leveldbIterator{b.ldb.NewIterator(&util.Range{Start: first, Limit: last}, nil)}, nil
} }
func (b *leveldbBackend) Put(key, val []byte) error { func (b *leveldbBackend) Put(key, val []byte) error {
@ -158,6 +159,14 @@ func (t *leveldbTransaction) flush() error {
return nil return nil
} }
type leveldbIterator struct {
iterator.Iterator
}
func (it *leveldbIterator) Error() error {
return wrapLeveldbErr(it.Iterator.Error())
}
// wrapLeveldbErr wraps errors so that the backend package can recognize them // wrapLeveldbErr wraps errors so that the backend package can recognize them
func wrapLeveldbErr(err error) error { func wrapLeveldbErr(err error) error {
if err == nil { if err == nil {