150 lines
2.8 KiB
Go
150 lines
2.8 KiB
Go
package tsm1
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
var errKeyCountChanged = errors.New("TSMIndexIterator: key count changed during iteration")
|
|
|
|
// TSMIndexIterator allows one to iterate over the TSM index.
|
|
type TSMIndexIterator struct {
|
|
b *faultBuffer
|
|
n int
|
|
d *indirectIndex
|
|
iter *readerOffsetsIterator
|
|
|
|
// if true, don't need to advance iter on the call to Next
|
|
first bool
|
|
peeked bool
|
|
|
|
ok bool
|
|
err error
|
|
|
|
offset uint32
|
|
eoffset uint32
|
|
|
|
// lazily loaded from offset and eoffset
|
|
key []byte
|
|
typ byte
|
|
entries []IndexEntry
|
|
}
|
|
|
|
// Next advances the iterator and reports if it is still valid.
|
|
func (t *TSMIndexIterator) Next() bool {
|
|
t.d.mu.RLock()
|
|
if n := len(t.d.ro.offsets); t.n != n {
|
|
t.err, t.ok = errKeyCountChanged, false
|
|
}
|
|
if !t.ok || t.err != nil {
|
|
t.d.mu.RUnlock()
|
|
return false
|
|
}
|
|
if !t.peeked && !t.first {
|
|
t.ok = t.iter.Next()
|
|
}
|
|
if !t.ok {
|
|
t.d.mu.RUnlock()
|
|
return false
|
|
}
|
|
|
|
t.peeked = false
|
|
t.first = false
|
|
|
|
t.offset = t.iter.Offset()
|
|
t.eoffset = t.iter.EntryOffset(t.b)
|
|
t.d.mu.RUnlock()
|
|
|
|
// reset lazy loaded state
|
|
t.key = nil
|
|
t.typ = 0
|
|
t.entries = t.entries[:0]
|
|
return true
|
|
}
|
|
|
|
// Seek points the iterator at the smallest key greater than or equal to the
|
|
// given key, returning true if it was an exact match. It returns false for
|
|
// ok if the key does not exist.
|
|
func (t *TSMIndexIterator) Seek(key []byte) (exact, ok bool) {
|
|
t.d.mu.RLock()
|
|
if n := len(t.d.ro.offsets); t.n != n {
|
|
t.err, t.ok = errKeyCountChanged, false
|
|
}
|
|
if t.err != nil {
|
|
t.d.mu.RUnlock()
|
|
return false, false
|
|
}
|
|
|
|
t.peeked = false
|
|
t.first = false
|
|
|
|
exact, t.ok = t.iter.Seek(key, t.b)
|
|
if !t.ok {
|
|
t.d.mu.RUnlock()
|
|
return false, false
|
|
}
|
|
|
|
t.offset = t.iter.Offset()
|
|
t.eoffset = t.iter.EntryOffset(t.b)
|
|
t.d.mu.RUnlock()
|
|
|
|
// reset lazy loaded state
|
|
t.key = nil
|
|
t.typ = 0
|
|
t.entries = t.entries[:0]
|
|
return exact, true
|
|
}
|
|
|
|
// Peek reports the next key or nil if there is not one or an error happened.
|
|
func (t *TSMIndexIterator) Peek() []byte {
|
|
if !t.ok || t.err != nil {
|
|
return nil
|
|
}
|
|
if !t.peeked {
|
|
t.ok = t.iter.Next()
|
|
t.peeked = true
|
|
}
|
|
|
|
if !t.ok {
|
|
return nil
|
|
}
|
|
|
|
return t.iter.Key(t.b)
|
|
}
|
|
|
|
// Key reports the current key.
|
|
func (t *TSMIndexIterator) Key() []byte {
|
|
if t.key == nil {
|
|
buf := t.b.access(t.offset, 0)
|
|
t.key = readKey(buf)
|
|
t.typ = buf[2+len(t.key)]
|
|
}
|
|
return t.key
|
|
}
|
|
|
|
// Type reports the current type.
|
|
func (t *TSMIndexIterator) Type() byte {
|
|
if t.key == nil {
|
|
buf := t.b.access(t.offset, 0)
|
|
t.key = readKey(buf)
|
|
t.typ = buf[2+len(t.key)]
|
|
}
|
|
return t.typ
|
|
}
|
|
|
|
// Entries reports the current list of entries.
|
|
func (t *TSMIndexIterator) Entries() []IndexEntry {
|
|
if len(t.entries) == 0 {
|
|
buf := t.b.access(t.eoffset, 0)
|
|
t.entries, t.err = readEntries(buf, t.entries)
|
|
}
|
|
if t.err != nil {
|
|
return nil
|
|
}
|
|
return t.entries
|
|
}
|
|
|
|
// Err reports if an error stopped the iteration.
|
|
func (t *TSMIndexIterator) Err() error {
|
|
return t.err
|
|
}
|