mirror of
https://github.com/btcsuite/btcd.git
synced 2025-03-13 19:37:39 +01:00
431 lines
9.1 KiB
Go
431 lines
9.1 KiB
Go
|
package engine
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
|
||
|
"github.com/syndtr/goleveldb/leveldb/errors"
|
||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||
|
)
|
||
|
|
||
|
type Iterator interface {
|
||
|
// First moves the iterator to the first key/value pair. If the iterator
|
||
|
// only contains one key/value pair then First and Last would moves
|
||
|
// to the same key/value pair.
|
||
|
// It returns whether such pair exist.
|
||
|
First() bool
|
||
|
|
||
|
// Last moves the iterator to the last key/value pair. If the iterator
|
||
|
// only contains one key/value pair then First and Last would moves
|
||
|
// to the same key/value pair.
|
||
|
// It returns whether such pair exist.
|
||
|
Last() bool
|
||
|
|
||
|
// Seek moves the iterator to the first key/value pair whose key is greater
|
||
|
// than or equal to the given key.
|
||
|
// It returns whether such pair exist.
|
||
|
//
|
||
|
// It is safe to modify the contents of the argument after Seek returns.
|
||
|
Seek(key []byte) bool
|
||
|
|
||
|
// Next moves the iterator to the next key/value pair.
|
||
|
// It returns false if the iterator is exhausted.
|
||
|
Next() bool
|
||
|
|
||
|
// Prev moves the iterator to the previous key/value pair.
|
||
|
// It returns false if the iterator is exhausted.
|
||
|
Prev() bool
|
||
|
|
||
|
// TODO: Remove this when ready.
|
||
|
Valid() bool
|
||
|
|
||
|
// Error returns any accumulated error. Exhausting all the key/value pairs
|
||
|
// is not considered to be an error.
|
||
|
Error() error
|
||
|
|
||
|
// Key returns the key of the current key/value pair, or nil if done.
|
||
|
// The caller should not modify the contents of the returned slice, and
|
||
|
// its contents may change on the next call to any 'seeks method'.
|
||
|
Key() []byte
|
||
|
|
||
|
// Value returns the value of the current key/value pair, or nil if done.
|
||
|
// The caller should not modify the contents of the returned slice, and
|
||
|
// its contents may change on the next call to any 'seeks method'.
|
||
|
Value() []byte
|
||
|
|
||
|
Releaser
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
ErrIterReleased = errors.New("iterator: iterator released")
|
||
|
)
|
||
|
|
||
|
type dir int
|
||
|
|
||
|
const (
|
||
|
dirReleased dir = iota - 1
|
||
|
dirSOI
|
||
|
dirEOI
|
||
|
dirBackward
|
||
|
dirForward
|
||
|
)
|
||
|
|
||
|
var _ Iterator = (*mergedIterator)(nil)
|
||
|
|
||
|
type mergedIterator struct {
|
||
|
cmp Comparer
|
||
|
iters []Iterator
|
||
|
strict bool
|
||
|
|
||
|
keys [][]byte
|
||
|
index int
|
||
|
dir dir
|
||
|
err error
|
||
|
errf func(err error)
|
||
|
releaser util.Releaser
|
||
|
}
|
||
|
|
||
|
func assertKey(key []byte) []byte {
|
||
|
if key == nil {
|
||
|
panic("leveldb/iterator: nil key")
|
||
|
}
|
||
|
return key
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) iterErr(iter Iterator) bool {
|
||
|
if err := iter.Error(); err != nil {
|
||
|
if i.errf != nil {
|
||
|
i.errf(err)
|
||
|
}
|
||
|
if i.strict || !errors.IsCorrupted(err) {
|
||
|
i.err = err
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Valid() bool {
|
||
|
return i.err == nil && i.dir > dirEOI
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) First() bool {
|
||
|
if i.err != nil {
|
||
|
return false
|
||
|
} else if i.dir == dirReleased {
|
||
|
i.err = ErrIterReleased
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for x, iter := range i.iters {
|
||
|
switch {
|
||
|
case iter.First():
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
}
|
||
|
i.dir = dirSOI
|
||
|
return i.next()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Last() bool {
|
||
|
if i.err != nil {
|
||
|
return false
|
||
|
} else if i.dir == dirReleased {
|
||
|
i.err = ErrIterReleased
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for x, iter := range i.iters {
|
||
|
switch {
|
||
|
case iter.Last():
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
}
|
||
|
i.dir = dirEOI
|
||
|
return i.prev()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Seek(key []byte) bool {
|
||
|
if i.err != nil {
|
||
|
return false
|
||
|
} else if i.dir == dirReleased {
|
||
|
i.err = ErrIterReleased
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for x, iter := range i.iters {
|
||
|
switch {
|
||
|
case iter.Seek(key):
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
}
|
||
|
i.dir = dirSOI
|
||
|
return i.next()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) next() bool {
|
||
|
var key []byte
|
||
|
if i.dir == dirForward {
|
||
|
key = i.keys[i.index]
|
||
|
}
|
||
|
for x, tkey := range i.keys {
|
||
|
if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) < 0) {
|
||
|
key = tkey
|
||
|
i.index = x
|
||
|
}
|
||
|
}
|
||
|
if key == nil {
|
||
|
i.dir = dirEOI
|
||
|
return false
|
||
|
}
|
||
|
i.dir = dirForward
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Next() bool {
|
||
|
if i.dir == dirEOI || i.err != nil {
|
||
|
return false
|
||
|
} else if i.dir == dirReleased {
|
||
|
i.err = ErrIterReleased
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
switch i.dir {
|
||
|
case dirSOI:
|
||
|
return i.First()
|
||
|
case dirBackward:
|
||
|
key := append([]byte{}, i.keys[i.index]...)
|
||
|
if !i.Seek(key) {
|
||
|
return false
|
||
|
}
|
||
|
return i.Next()
|
||
|
}
|
||
|
|
||
|
x := i.index
|
||
|
iter := i.iters[x]
|
||
|
switch {
|
||
|
case iter.Next():
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
return i.next()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) prev() bool {
|
||
|
var key []byte
|
||
|
if i.dir == dirBackward {
|
||
|
key = i.keys[i.index]
|
||
|
}
|
||
|
for x, tkey := range i.keys {
|
||
|
if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) > 0) {
|
||
|
key = tkey
|
||
|
i.index = x
|
||
|
}
|
||
|
}
|
||
|
if key == nil {
|
||
|
i.dir = dirSOI
|
||
|
return false
|
||
|
}
|
||
|
i.dir = dirBackward
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Prev() bool {
|
||
|
if i.dir == dirSOI || i.err != nil {
|
||
|
return false
|
||
|
} else if i.dir == dirReleased {
|
||
|
i.err = ErrIterReleased
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
switch i.dir {
|
||
|
case dirEOI:
|
||
|
return i.Last()
|
||
|
case dirForward:
|
||
|
key := append([]byte{}, i.keys[i.index]...)
|
||
|
for x, iter := range i.iters {
|
||
|
if x == i.index {
|
||
|
continue
|
||
|
}
|
||
|
seek := iter.Seek(key)
|
||
|
switch {
|
||
|
case seek && iter.Prev(), !seek && iter.Last():
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
x := i.index
|
||
|
iter := i.iters[x]
|
||
|
switch {
|
||
|
case iter.Prev():
|
||
|
i.keys[x] = assertKey(iter.Key())
|
||
|
case i.iterErr(iter):
|
||
|
return false
|
||
|
default:
|
||
|
i.keys[x] = nil
|
||
|
}
|
||
|
return i.prev()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Key() []byte {
|
||
|
if i.err != nil || i.dir <= dirEOI {
|
||
|
return nil
|
||
|
}
|
||
|
return i.keys[i.index]
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Value() []byte {
|
||
|
if i.err != nil || i.dir <= dirEOI {
|
||
|
return nil
|
||
|
}
|
||
|
return i.iters[i.index].Value()
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Release() {
|
||
|
if i.dir != dirReleased {
|
||
|
i.dir = dirReleased
|
||
|
for _, iter := range i.iters {
|
||
|
iter.Release()
|
||
|
}
|
||
|
i.iters = nil
|
||
|
i.keys = nil
|
||
|
if i.releaser != nil {
|
||
|
i.releaser.Release()
|
||
|
i.releaser = nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) SetReleaser(releaser util.Releaser) {
|
||
|
if i.dir == dirReleased {
|
||
|
panic(util.ErrReleased)
|
||
|
}
|
||
|
if i.releaser != nil && releaser != nil {
|
||
|
panic(util.ErrHasReleaser)
|
||
|
}
|
||
|
i.releaser = releaser
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) Error() error {
|
||
|
return i.err
|
||
|
}
|
||
|
|
||
|
func (i *mergedIterator) SetErrorCallback(f func(err error)) {
|
||
|
i.errf = f
|
||
|
}
|
||
|
|
||
|
// NewMergedIterator returns an iterator that merges its input. Walking the
|
||
|
// resultant iterator will return all key/value pairs of all input iterators
|
||
|
// in strictly increasing key order, as defined by cmp.
|
||
|
// The input's key ranges may overlap, but there are assumed to be no duplicate
|
||
|
// keys: if iters[i] contains a key k then iters[j] will not contain that key k.
|
||
|
// None of the iters may be nil.
|
||
|
//
|
||
|
// If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true)
|
||
|
// won't be ignored and will halt 'merged iterator', otherwise the iterator will
|
||
|
// continue to the next 'input iterator'.
|
||
|
func NewMergedIterator(iters []Iterator, cmp Comparer, strict bool) Iterator {
|
||
|
return &mergedIterator{
|
||
|
iters: iters,
|
||
|
cmp: cmp,
|
||
|
strict: strict,
|
||
|
keys: make([][]byte, len(iters)),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Comparer interface {
|
||
|
Compare(a, b []byte) int
|
||
|
|
||
|
Name() string
|
||
|
|
||
|
Separator(dst, a, b []byte) []byte
|
||
|
|
||
|
Successor(dst, b []byte) []byte
|
||
|
}
|
||
|
|
||
|
type bytesComparer struct{}
|
||
|
|
||
|
func (bytesComparer) Compare(a, b []byte) int {
|
||
|
return bytes.Compare(a, b)
|
||
|
}
|
||
|
|
||
|
func (bytesComparer) Name() string {
|
||
|
return "leveldb.BytewiseComparator"
|
||
|
}
|
||
|
|
||
|
func (bytesComparer) Separator(dst, a, b []byte) []byte {
|
||
|
i, n := 0, len(a)
|
||
|
if n > len(b) {
|
||
|
n = len(b)
|
||
|
}
|
||
|
for ; i < n && a[i] == b[i]; i++ {
|
||
|
}
|
||
|
if i >= n {
|
||
|
// Do not shorten if one string is a prefix of the other
|
||
|
} else if c := a[i]; c < 0xff && c+1 < b[i] {
|
||
|
dst = append(dst, a[:i+1]...)
|
||
|
dst[len(dst)-1]++
|
||
|
return dst
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (bytesComparer) Successor(dst, b []byte) []byte {
|
||
|
for i, c := range b {
|
||
|
if c != 0xff {
|
||
|
dst = append(dst, b[:i+1]...)
|
||
|
dst[len(dst)-1]++
|
||
|
return dst
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// DefaultComparer are default implementation of the Comparer interface.
|
||
|
// It uses the natural ordering, consistent with bytes.Compare.
|
||
|
var DefaultComparer = bytesComparer{}
|
||
|
|
||
|
// Range is a key range.
|
||
|
type Range struct {
|
||
|
// Start of the key range, include in the range.
|
||
|
Start []byte
|
||
|
|
||
|
// Limit of the key range, not include in the range.
|
||
|
Limit []byte
|
||
|
}
|
||
|
|
||
|
// BytesPrefix returns key range that satisfy the given prefix.
|
||
|
// This only applicable for the standard 'bytes comparer'.
|
||
|
func BytesPrefix(prefix []byte) *Range {
|
||
|
var limit []byte
|
||
|
for i := len(prefix) - 1; i >= 0; i-- {
|
||
|
c := prefix[i]
|
||
|
if c < 0xff {
|
||
|
limit = make([]byte, i+1)
|
||
|
copy(limit, prefix)
|
||
|
limit[i] = c + 1
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return &Range{prefix, limit}
|
||
|
}
|