influxdb/tsdb/tsm1/reader_index_iterator.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
}