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} }