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