forked from TrueCloudLab/neoneo-go
storage: generalize Level/Bolt seek implementations
Too much in common. Just refactoring. no functional changes.
This commit is contained in:
parent
a5f8b8870a
commit
51b804ab0e
3 changed files with 51 additions and 60 deletions
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -110,44 +109,30 @@ func (s *BoltDBStore) PutChangeSet(puts map[string][]byte) error {
|
||||||
|
|
||||||
// Seek implements the Store interface.
|
// Seek implements the Store interface.
|
||||||
func (s *BoltDBStore) Seek(rng SeekRange, f func(k, v []byte) bool) {
|
func (s *BoltDBStore) Seek(rng SeekRange, f func(k, v []byte) bool) {
|
||||||
start := make([]byte, len(rng.Prefix)+len(rng.Start))
|
rang := seekRangeToPrefixes(rng)
|
||||||
copy(start, rng.Prefix)
|
|
||||||
copy(start[len(rng.Prefix):], rng.Start)
|
|
||||||
if rng.Backwards {
|
|
||||||
s.seekBackwards(rng.Prefix, start, f)
|
|
||||||
} else {
|
|
||||||
s.seek(rng.Prefix, start, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoltDBStore) seek(key []byte, start []byte, f func(k, v []byte) bool) {
|
|
||||||
prefix := util.BytesPrefix(key)
|
|
||||||
prefix.Start = start
|
|
||||||
err := s.db.View(func(tx *bbolt.Tx) error {
|
err := s.db.View(func(tx *bbolt.Tx) error {
|
||||||
|
var (
|
||||||
|
k, v []byte
|
||||||
|
next func() ([]byte, []byte)
|
||||||
|
)
|
||||||
|
|
||||||
c := tx.Bucket(Bucket).Cursor()
|
c := tx.Bucket(Bucket).Cursor()
|
||||||
for k, v := c.Seek(prefix.Start); k != nil && (len(prefix.Limit) == 0 || bytes.Compare(k, prefix.Limit) <= 0); k, v = c.Next() {
|
|
||||||
if !f(k, v) {
|
if !rng.Backwards {
|
||||||
break
|
k, v = c.Seek(rang.Start)
|
||||||
|
next = c.Next
|
||||||
|
} else {
|
||||||
|
if len(rang.Limit) == 0 {
|
||||||
|
lastKey, _ := c.Last()
|
||||||
|
k, v = c.Seek(lastKey)
|
||||||
|
} else {
|
||||||
|
c.Seek(rang.Limit)
|
||||||
|
k, v = c.Prev()
|
||||||
}
|
}
|
||||||
|
next = c.Prev
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoltDBStore) seekBackwards(key []byte, start []byte, f func(k, v []byte) bool) {
|
for ; k != nil && bytes.HasPrefix(k, rng.Prefix) && (len(rang.Limit) == 0 || bytes.Compare(k, rang.Limit) <= 0); k, v = next() {
|
||||||
err := s.db.View(func(tx *bbolt.Tx) error {
|
|
||||||
c := tx.Bucket(Bucket).Cursor()
|
|
||||||
// Move cursor to the first kv pair which is followed by the pair matching the specified prefix.
|
|
||||||
if len(start) == 0 {
|
|
||||||
lastKey, _ := c.Last()
|
|
||||||
start = lastKey
|
|
||||||
}
|
|
||||||
rng := util.BytesPrefix(start) // in fact, we only need limit based on start slice to iterate backwards starting from this limit
|
|
||||||
c.Seek(rng.Limit)
|
|
||||||
for k, v := c.Prev(); k != nil && bytes.HasPrefix(k, key); k, v = c.Prev() {
|
|
||||||
if !f(k, v) {
|
if !f(k, v) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/filter"
|
"github.com/syndtr/goleveldb/leveldb/filter"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LevelDBOptions configuration for LevelDB.
|
// LevelDBOptions configuration for LevelDB.
|
||||||
|
@ -83,34 +82,21 @@ func (s *LevelDBStore) PutChangeSet(puts map[string][]byte) error {
|
||||||
|
|
||||||
// Seek implements the Store interface.
|
// Seek implements the Store interface.
|
||||||
func (s *LevelDBStore) Seek(rng SeekRange, f func(k, v []byte) bool) {
|
func (s *LevelDBStore) Seek(rng SeekRange, f func(k, v []byte) bool) {
|
||||||
start := make([]byte, len(rng.Prefix)+len(rng.Start))
|
var (
|
||||||
copy(start, rng.Prefix)
|
next func() bool
|
||||||
copy(start[len(rng.Prefix):], rng.Start)
|
ok bool
|
||||||
if rng.Backwards {
|
iter = s.db.NewIterator(seekRangeToPrefixes(rng), nil)
|
||||||
s.seekBackwards(rng.Prefix, start, f)
|
)
|
||||||
|
|
||||||
|
if !rng.Backwards {
|
||||||
|
ok = iter.Next()
|
||||||
|
next = iter.Next
|
||||||
} else {
|
} else {
|
||||||
s.seek(rng.Prefix, start, f)
|
ok = iter.Last()
|
||||||
|
next = iter.Prev
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStore) seek(key []byte, start []byte, f func(k, v []byte) bool) {
|
for ; ok; ok = next() {
|
||||||
prefix := util.BytesPrefix(key)
|
|
||||||
prefix.Start = start
|
|
||||||
iter := s.db.NewIterator(prefix, nil)
|
|
||||||
for iter.Next() {
|
|
||||||
if !f(iter.Key(), iter.Value()) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iter.Release()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LevelDBStore) seekBackwards(key []byte, start []byte, f func(k, v []byte) bool) {
|
|
||||||
iRange := util.BytesPrefix(start)
|
|
||||||
iRange.Start = key
|
|
||||||
|
|
||||||
iter := s.db.NewIterator(iRange, nil)
|
|
||||||
for ok := iter.Last(); ok; ok = iter.Prev() {
|
|
||||||
if !f(iter.Key(), iter.Value()) {
|
if !f(iter.Key(), iter.Value()) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KeyPrefix constants.
|
// KeyPrefix constants.
|
||||||
|
@ -133,6 +135,24 @@ func AppendPrefixInt(k KeyPrefix, n int) []byte {
|
||||||
return AppendPrefix(k, b)
|
return AppendPrefix(k, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func seekRangeToPrefixes(sr SeekRange) *util.Range {
|
||||||
|
var (
|
||||||
|
rang *util.Range
|
||||||
|
start = make([]byte, len(sr.Prefix)+len(sr.Start))
|
||||||
|
)
|
||||||
|
copy(start, sr.Prefix)
|
||||||
|
copy(start[len(sr.Prefix):], sr.Start)
|
||||||
|
|
||||||
|
if !sr.Backwards {
|
||||||
|
rang = util.BytesPrefix(sr.Prefix)
|
||||||
|
rang.Start = start
|
||||||
|
} else {
|
||||||
|
rang = util.BytesPrefix(start)
|
||||||
|
rang.Start = sr.Prefix
|
||||||
|
}
|
||||||
|
return rang
|
||||||
|
}
|
||||||
|
|
||||||
// NewStore creates storage with preselected in configuration database type.
|
// NewStore creates storage with preselected in configuration database type.
|
||||||
func NewStore(cfg DBConfiguration) (Store, error) {
|
func NewStore(cfg DBConfiguration) (Store, error) {
|
||||||
var store Store
|
var store Store
|
||||||
|
|
Loading…
Reference in a new issue