1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
10 "github.com/syndtr/goleveldb/leveldb/comparer"
11 "github.com/syndtr/goleveldb/leveldb/errors"
12 "github.com/syndtr/goleveldb/leveldb/util"
18 dirReleased dir = iota - 1
25 type mergedIterator struct {
35 releaser util.Releaser
38 func assertKey(key []byte) []byte {
40 panic("leveldb/iterator: nil key")
45 func (i *mergedIterator) iterErr(iter Iterator) bool {
46 if err := iter.Error(); err != nil {
50 if i.strict || !errors.IsCorrupted(err) {
58 func (i *mergedIterator) Valid() bool {
59 return i.err == nil && i.dir > dirEOI
62 func (i *mergedIterator) First() bool {
65 } else if i.dir == dirReleased {
66 i.err = ErrIterReleased
70 for x, iter := range i.iters {
73 i.keys[x] = assertKey(iter.Key())
84 func (i *mergedIterator) Last() bool {
87 } else if i.dir == dirReleased {
88 i.err = ErrIterReleased
92 for x, iter := range i.iters {
95 i.keys[x] = assertKey(iter.Key())
106 func (i *mergedIterator) Seek(key []byte) bool {
109 } else if i.dir == dirReleased {
110 i.err = ErrIterReleased
114 for x, iter := range i.iters {
117 i.keys[x] = assertKey(iter.Key())
118 case i.iterErr(iter):
128 func (i *mergedIterator) next() bool {
130 if i.dir == dirForward {
131 key = i.keys[i.index]
133 for x, tkey := range i.keys {
134 if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) < 0) {
147 func (i *mergedIterator) Next() bool {
148 if i.dir == dirEOI || i.err != nil {
150 } else if i.dir == dirReleased {
151 i.err = ErrIterReleased
159 key := append([]byte{}, i.keys[i.index]...)
170 i.keys[x] = assertKey(iter.Key())
171 case i.iterErr(iter):
179 func (i *mergedIterator) prev() bool {
181 if i.dir == dirBackward {
182 key = i.keys[i.index]
184 for x, tkey := range i.keys {
185 if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) > 0) {
198 func (i *mergedIterator) Prev() bool {
199 if i.dir == dirSOI || i.err != nil {
201 } else if i.dir == dirReleased {
202 i.err = ErrIterReleased
210 key := append([]byte{}, i.keys[i.index]...)
211 for x, iter := range i.iters {
215 seek := iter.Seek(key)
217 case seek && iter.Prev(), !seek && iter.Last():
218 i.keys[x] = assertKey(iter.Key())
219 case i.iterErr(iter):
231 i.keys[x] = assertKey(iter.Key())
232 case i.iterErr(iter):
240 func (i *mergedIterator) Key() []byte {
241 if i.err != nil || i.dir <= dirEOI {
244 return i.keys[i.index]
247 func (i *mergedIterator) Value() []byte {
248 if i.err != nil || i.dir <= dirEOI {
251 return i.iters[i.index].Value()
254 func (i *mergedIterator) Release() {
255 if i.dir != dirReleased {
257 for _, iter := range i.iters {
262 if i.releaser != nil {
269 func (i *mergedIterator) SetReleaser(releaser util.Releaser) {
270 if i.dir == dirReleased {
271 panic(util.ErrReleased)
273 if i.releaser != nil && releaser != nil {
274 panic(util.ErrHasReleaser)
276 i.releaser = releaser
279 func (i *mergedIterator) Error() error {
283 func (i *mergedIterator) SetErrorCallback(f func(err error)) {
287 // NewMergedIterator returns an iterator that merges its input. Walking the
288 // resultant iterator will return all key/value pairs of all input iterators
289 // in strictly increasing key order, as defined by cmp.
290 // The input's key ranges may overlap, but there are assumed to be no duplicate
291 // keys: if iters[i] contains a key k then iters[j] will not contain that key k.
292 // None of the iters may be nil.
294 // If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true)
295 // won't be ignored and will halt 'merged iterator', otherwise the iterator will
296 // continue to the next 'input iterator'.
297 func NewMergedIterator(iters []Iterator, cmp comparer.Comparer, strict bool) Iterator {
298 return &mergedIterator{
302 keys: make([][]byte, len(iters)),