1// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
2// All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7package iterator
8
9import (
10	"github.com/syndtr/goleveldb/leveldb/errors"
11	"github.com/syndtr/goleveldb/leveldb/util"
12)
13
14// IteratorIndexer is the interface that wraps CommonIterator and basic Get
15// method. IteratorIndexer provides index for indexed iterator.
16type IteratorIndexer interface {
17	CommonIterator
18
19	// Get returns a new data iterator for the current position, or nil if
20	// done.
21	Get() Iterator
22}
23
24type indexedIterator struct {
25	util.BasicReleaser
26	index  IteratorIndexer
27	strict bool
28
29	data   Iterator
30	err    error
31	errf   func(err error)
32	closed bool
33}
34
35func (i *indexedIterator) setData() {
36	if i.data != nil {
37		i.data.Release()
38	}
39	i.data = i.index.Get()
40}
41
42func (i *indexedIterator) clearData() {
43	if i.data != nil {
44		i.data.Release()
45	}
46	i.data = nil
47}
48
49func (i *indexedIterator) indexErr() {
50	if err := i.index.Error(); err != nil {
51		if i.errf != nil {
52			i.errf(err)
53		}
54		i.err = err
55	}
56}
57
58func (i *indexedIterator) dataErr() bool {
59	if err := i.data.Error(); err != nil {
60		if i.errf != nil {
61			i.errf(err)
62		}
63		if i.strict || !errors.IsCorrupted(err) {
64			i.err = err
65			return true
66		}
67	}
68	return false
69}
70
71func (i *indexedIterator) Valid() bool {
72	return i.data != nil && i.data.Valid()
73}
74
75func (i *indexedIterator) First() bool {
76	if i.err != nil {
77		return false
78	} else if i.Released() {
79		i.err = ErrIterReleased
80		return false
81	}
82
83	if !i.index.First() {
84		i.indexErr()
85		i.clearData()
86		return false
87	}
88	i.setData()
89	return i.Next()
90}
91
92func (i *indexedIterator) Last() bool {
93	if i.err != nil {
94		return false
95	} else if i.Released() {
96		i.err = ErrIterReleased
97		return false
98	}
99
100	if !i.index.Last() {
101		i.indexErr()
102		i.clearData()
103		return false
104	}
105	i.setData()
106	if !i.data.Last() {
107		if i.dataErr() {
108			return false
109		}
110		i.clearData()
111		return i.Prev()
112	}
113	return true
114}
115
116func (i *indexedIterator) Seek(key []byte) bool {
117	if i.err != nil {
118		return false
119	} else if i.Released() {
120		i.err = ErrIterReleased
121		return false
122	}
123
124	if !i.index.Seek(key) {
125		i.indexErr()
126		i.clearData()
127		return false
128	}
129	i.setData()
130	if !i.data.Seek(key) {
131		if i.dataErr() {
132			return false
133		}
134		i.clearData()
135		return i.Next()
136	}
137	return true
138}
139
140func (i *indexedIterator) Next() bool {
141	if i.err != nil {
142		return false
143	} else if i.Released() {
144		i.err = ErrIterReleased
145		return false
146	}
147
148	switch {
149	case i.data != nil && !i.data.Next():
150		if i.dataErr() {
151			return false
152		}
153		i.clearData()
154		fallthrough
155	case i.data == nil:
156		if !i.index.Next() {
157			i.indexErr()
158			return false
159		}
160		i.setData()
161		return i.Next()
162	}
163	return true
164}
165
166func (i *indexedIterator) Prev() bool {
167	if i.err != nil {
168		return false
169	} else if i.Released() {
170		i.err = ErrIterReleased
171		return false
172	}
173
174	switch {
175	case i.data != nil && !i.data.Prev():
176		if i.dataErr() {
177			return false
178		}
179		i.clearData()
180		fallthrough
181	case i.data == nil:
182		if !i.index.Prev() {
183			i.indexErr()
184			return false
185		}
186		i.setData()
187		if !i.data.Last() {
188			if i.dataErr() {
189				return false
190			}
191			i.clearData()
192			return i.Prev()
193		}
194	}
195	return true
196}
197
198func (i *indexedIterator) Key() []byte {
199	if i.data == nil {
200		return nil
201	}
202	return i.data.Key()
203}
204
205func (i *indexedIterator) Value() []byte {
206	if i.data == nil {
207		return nil
208	}
209	return i.data.Value()
210}
211
212func (i *indexedIterator) Release() {
213	i.clearData()
214	i.index.Release()
215	i.BasicReleaser.Release()
216}
217
218func (i *indexedIterator) Error() error {
219	if i.err != nil {
220		return i.err
221	}
222	if err := i.index.Error(); err != nil {
223		return err
224	}
225	return nil
226}
227
228func (i *indexedIterator) SetErrorCallback(f func(err error)) {
229	i.errf = f
230}
231
232// NewIndexedIterator returns an 'indexed iterator'. An index is iterator
233// that returns another iterator, a 'data iterator'. A 'data iterator' is the
234// iterator that contains actual key/value pairs.
235//
236// If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true)
237// won't be ignored and will halt 'indexed iterator', otherwise the iterator will
238// continue to the next 'data iterator'. Corruption on 'index iterator' will not be
239// ignored and will halt the iterator.
240func NewIndexedIterator(index IteratorIndexer, strict bool) Iterator {
241	return &indexedIterator{index: index, strict: strict}
242}
243