2014-07-06 14:46:48 +02:00
|
|
|
// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
package iterator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// IteratorIndexer is the interface that wraps CommonIterator and basic Get
|
|
|
|
// method. IteratorIndexer provides index for indexed iterator.
|
|
|
|
type IteratorIndexer interface {
|
|
|
|
CommonIterator
|
|
|
|
|
|
|
|
// Get returns a new data iterator for the current position, or nil if
|
|
|
|
// done.
|
|
|
|
Get() Iterator
|
|
|
|
}
|
|
|
|
|
|
|
|
type indexedIterator struct {
|
|
|
|
util.BasicReleaser
|
|
|
|
index IteratorIndexer
|
|
|
|
strict bool
|
|
|
|
strictGet bool
|
|
|
|
|
2014-10-06 22:07:33 +02:00
|
|
|
data Iterator
|
|
|
|
err error
|
|
|
|
errf func(err error)
|
|
|
|
closed bool
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) setData() {
|
|
|
|
if i.data != nil {
|
|
|
|
i.data.Release()
|
|
|
|
}
|
|
|
|
i.data = i.index.Get()
|
|
|
|
if i.strictGet {
|
|
|
|
if err := i.data.Error(); err != nil {
|
|
|
|
i.err = err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) clearData() {
|
|
|
|
if i.data != nil {
|
|
|
|
i.data.Release()
|
|
|
|
}
|
|
|
|
i.data = nil
|
|
|
|
}
|
|
|
|
|
2014-10-06 22:07:33 +02:00
|
|
|
func (i *indexedIterator) indexErr() {
|
|
|
|
if err := i.index.Error(); err != nil {
|
|
|
|
if i.errf != nil {
|
|
|
|
i.errf(err)
|
|
|
|
}
|
|
|
|
i.err = err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 14:46:48 +02:00
|
|
|
func (i *indexedIterator) dataErr() bool {
|
|
|
|
if i.errf != nil {
|
|
|
|
if err := i.data.Error(); err != nil {
|
|
|
|
i.errf(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i.strict {
|
|
|
|
if err := i.data.Error(); err != nil {
|
|
|
|
i.err = err
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Valid() bool {
|
|
|
|
return i.data != nil && i.data.Valid()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) First() bool {
|
|
|
|
if i.err != nil {
|
|
|
|
return false
|
2014-10-06 22:07:33 +02:00
|
|
|
} else if i.Released() {
|
|
|
|
i.err = ErrIterReleased
|
|
|
|
return false
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !i.index.First() {
|
2014-10-06 22:07:33 +02:00
|
|
|
i.indexErr()
|
2014-07-06 14:46:48 +02:00
|
|
|
i.clearData()
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.setData()
|
|
|
|
return i.Next()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Last() bool {
|
|
|
|
if i.err != nil {
|
|
|
|
return false
|
2014-10-06 22:07:33 +02:00
|
|
|
} else if i.Released() {
|
|
|
|
i.err = ErrIterReleased
|
|
|
|
return false
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !i.index.Last() {
|
2014-10-06 22:07:33 +02:00
|
|
|
i.indexErr()
|
2014-07-06 14:46:48 +02:00
|
|
|
i.clearData()
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.setData()
|
|
|
|
if !i.data.Last() {
|
|
|
|
if i.dataErr() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.clearData()
|
|
|
|
return i.Prev()
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Seek(key []byte) bool {
|
|
|
|
if i.err != nil {
|
|
|
|
return false
|
2014-10-06 22:07:33 +02:00
|
|
|
} else if i.Released() {
|
|
|
|
i.err = ErrIterReleased
|
|
|
|
return false
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !i.index.Seek(key) {
|
2014-10-06 22:07:33 +02:00
|
|
|
i.indexErr()
|
2014-07-06 14:46:48 +02:00
|
|
|
i.clearData()
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.setData()
|
|
|
|
if !i.data.Seek(key) {
|
|
|
|
if i.dataErr() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.clearData()
|
|
|
|
return i.Next()
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Next() bool {
|
|
|
|
if i.err != nil {
|
|
|
|
return false
|
2014-10-06 22:07:33 +02:00
|
|
|
} else if i.Released() {
|
|
|
|
i.err = ErrIterReleased
|
|
|
|
return false
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case i.data != nil && !i.data.Next():
|
|
|
|
if i.dataErr() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.clearData()
|
|
|
|
fallthrough
|
|
|
|
case i.data == nil:
|
|
|
|
if !i.index.Next() {
|
2014-10-06 22:07:33 +02:00
|
|
|
i.indexErr()
|
2014-07-06 14:46:48 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.setData()
|
|
|
|
return i.Next()
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Prev() bool {
|
|
|
|
if i.err != nil {
|
|
|
|
return false
|
2014-10-06 22:07:33 +02:00
|
|
|
} else if i.Released() {
|
|
|
|
i.err = ErrIterReleased
|
|
|
|
return false
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case i.data != nil && !i.data.Prev():
|
|
|
|
if i.dataErr() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.clearData()
|
|
|
|
fallthrough
|
|
|
|
case i.data == nil:
|
|
|
|
if !i.index.Prev() {
|
2014-10-06 22:07:33 +02:00
|
|
|
i.indexErr()
|
2014-07-06 14:46:48 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.setData()
|
|
|
|
if !i.data.Last() {
|
|
|
|
if i.dataErr() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i.clearData()
|
|
|
|
return i.Prev()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Key() []byte {
|
|
|
|
if i.data == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return i.data.Key()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Value() []byte {
|
|
|
|
if i.data == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return i.data.Value()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Release() {
|
|
|
|
i.clearData()
|
|
|
|
i.index.Release()
|
|
|
|
i.BasicReleaser.Release()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) Error() error {
|
|
|
|
if i.err != nil {
|
|
|
|
return i.err
|
|
|
|
}
|
|
|
|
if err := i.index.Error(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *indexedIterator) SetErrorCallback(f func(err error)) {
|
|
|
|
i.errf = f
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewIndexedIterator returns an indexed iterator. An index is iterator
|
|
|
|
// that returns another iterator, a data iterator. A data iterator is the
|
|
|
|
// iterator that contains actual key/value pairs.
|
|
|
|
//
|
|
|
|
// If strict is true then error yield by data iterator will halt the indexed
|
|
|
|
// iterator, on contrary if strict is false then the indexed iterator will
|
|
|
|
// ignore those error and move on to the next index. If strictGet is true and
|
|
|
|
// index.Get() yield an 'error iterator' then the indexed iterator will be halted.
|
|
|
|
// An 'error iterator' is iterator which its Error() method always return non-nil
|
|
|
|
// even before any 'seeks method' is called.
|
|
|
|
func NewIndexedIterator(index IteratorIndexer, strict, strictGet bool) Iterator {
|
|
|
|
return &indexedIterator{index: index, strict: strict, strictGet: strictGet}
|
|
|
|
}
|