mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
145 lines
3.4 KiB
Go
145 lines
3.4 KiB
Go
package tstore
|
|
|
|
import (
|
|
"github.com/featurebasedb/featurebase/v3/bufferpool"
|
|
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
|
|
"github.com/featurebasedb/featurebase/v3/vprint"
|
|
)
|
|
|
|
type stackItem struct {
|
|
n *BTreeNode
|
|
i int
|
|
}
|
|
|
|
type TstoreIterator interface {
|
|
Next() bool
|
|
Item() (*BTreeTuple, Sortable)
|
|
Dispose()
|
|
}
|
|
|
|
type RangeIterator struct {
|
|
tree *BTree
|
|
node *BTreeNode
|
|
schema types.Schema
|
|
from Sortable
|
|
to Sortable
|
|
item *BTreeTuple
|
|
key Sortable
|
|
//
|
|
cursor int
|
|
done bool
|
|
err error
|
|
}
|
|
|
|
func (b *BTree) NewRangeIterator(first, last Sortable) (*RangeIterator, error) {
|
|
root, err := b.fetchNode(b.rootNode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewRangeIterator(b, root, first, last, b.schema), nil
|
|
}
|
|
|
|
func NewRangeIterator(tree *BTree, initialNode *BTreeNode, from, to Sortable, schema types.Schema) *RangeIterator {
|
|
r := &RangeIterator{
|
|
tree: tree,
|
|
node: initialNode,
|
|
schema: schema,
|
|
from: from,
|
|
to: to,
|
|
}
|
|
r.Seek(from)
|
|
return r
|
|
}
|
|
|
|
func (iter *RangeIterator) Dump() {
|
|
vprint.VV("id:%v sc:%v ls:%v", iter.node.page.ID(), iter.node.slotCount(), iter.node.latchState())
|
|
}
|
|
|
|
func (iter *RangeIterator) Dispose() {
|
|
if iter.node.latchState() != bufferpool.None {
|
|
iter.node.releaseReadLatch()
|
|
iter.tree.unpin(iter.node)
|
|
}
|
|
}
|
|
|
|
func (iter *RangeIterator) Seek(key Sortable) {
|
|
iter.node, iter.err = iter.tree.fetchNode(iter.tree.rootNode)
|
|
if iter.err != nil {
|
|
return
|
|
}
|
|
iter.node.takeReadLatch()
|
|
iter.done, iter.err = iter.seek(iter.node, iter.schema, key)
|
|
}
|
|
|
|
func (iter *RangeIterator) seek(currentNode *BTreeNode, schema types.Schema, key Sortable) (bool, error) {
|
|
if currentNode.isLeaf() {
|
|
iter.node = currentNode
|
|
c, _ := currentNode.findKey(key)
|
|
iter.cursor = c - 1
|
|
return c == currentNode.slotCount(), nil
|
|
}
|
|
nodePtr := iter.tree.findNextPointer(currentNode, key)
|
|
node, err := iter.tree.fetchNode(nodePtr)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
node.takeReadLatch()
|
|
currentNode.releaseReadLatch()
|
|
iter.tree.unpin(currentNode)
|
|
return iter.seek(node, schema, key)
|
|
}
|
|
|
|
func (iter *RangeIterator) Item() (*BTreeTuple, Sortable) {
|
|
return iter.item, iter.key
|
|
}
|
|
|
|
func (iter *RangeIterator) Next() bool {
|
|
if iter.done {
|
|
return false
|
|
}
|
|
iter.cursor++
|
|
if iter.cursor == iter.node.slotCount() {
|
|
page := iter.node.page.ReadNextPointer()
|
|
iter.node.releaseReadLatch()
|
|
iter.tree.unpin(iter.node)
|
|
if page.Page == bufferpool.INVALID_PAGE { // at the end
|
|
return false
|
|
}
|
|
n, err := iter.tree.fetchNode(page)
|
|
iter.err = err
|
|
if iter.err != nil {
|
|
return false
|
|
}
|
|
iter.node = n
|
|
iter.node.takeReadLatch()
|
|
iter.cursor = 0
|
|
}
|
|
iter.key, iter.item, iter.err = iter.tree.getTuple(iter.node, int(iter.cursor), iter.schema)
|
|
return iter.key.Less(iter.to) && iter.err == nil
|
|
}
|
|
|
|
// TODO(twg) 2023/04/05 untested just added while it was top of mind
|
|
func (iter *RangeIterator) Prev() bool {
|
|
if iter.done {
|
|
return false
|
|
}
|
|
iter.cursor--
|
|
if iter.cursor < 0 {
|
|
page := iter.node.page.ReadPrevPointer()
|
|
iter.node.releaseReadLatch()
|
|
iter.tree.unpin(iter.node)
|
|
if page.Page == bufferpool.INVALID_PAGE { // at the end
|
|
return false
|
|
}
|
|
n, err := iter.tree.fetchNode(page)
|
|
iter.err = err
|
|
if iter.err != nil {
|
|
return false
|
|
}
|
|
iter.node = n
|
|
iter.node.takeReadLatch()
|
|
iter.cursor = iter.node.slotCount() - 1
|
|
}
|
|
iter.key, iter.item, iter.err = iter.tree.getTuple(iter.node, int(iter.cursor), iter.schema)
|
|
return iter.from.Less(iter.key) && iter.err == nil
|
|
}
|