| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
- * SPDX-License-Identifier: Apache-2.0
- */
- package table
- import (
- "bytes"
- "github.com/dgraph-io/badger/v4/y"
- )
- // MergeIterator merges multiple iterators.
- // NOTE: MergeIterator owns the array of iterators and is responsible for closing them.
- type MergeIterator struct {
- left node
- right node
- small *node
- curKey []byte
- reverse bool
- }
- type node struct {
- valid bool
- key []byte
- iter y.Iterator
- // The two iterators are type asserted from `y.Iterator`, used to inline more function calls.
- // Calling functions on concrete types is much faster (about 25-30%) than calling the
- // interface's function.
- merge *MergeIterator
- concat *ConcatIterator
- }
- func (n *node) setIterator(iter y.Iterator) {
- n.iter = iter
- // It's okay if the type assertion below fails and n.merge/n.concat are set to nil.
- // We handle the nil values of merge and concat in all the methods.
- n.merge, _ = iter.(*MergeIterator)
- n.concat, _ = iter.(*ConcatIterator)
- }
- func (n *node) setKey() {
- switch {
- case n.merge != nil:
- n.valid = n.merge.small.valid
- if n.valid {
- n.key = n.merge.small.key
- }
- case n.concat != nil:
- n.valid = n.concat.Valid()
- if n.valid {
- n.key = n.concat.Key()
- }
- default:
- n.valid = n.iter.Valid()
- if n.valid {
- n.key = n.iter.Key()
- }
- }
- }
- func (n *node) next() {
- switch {
- case n.merge != nil:
- n.merge.Next()
- case n.concat != nil:
- n.concat.Next()
- default:
- n.iter.Next()
- }
- n.setKey()
- }
- func (n *node) rewind() {
- n.iter.Rewind()
- n.setKey()
- }
- func (n *node) seek(key []byte) {
- n.iter.Seek(key)
- n.setKey()
- }
- func (mi *MergeIterator) fix() {
- if !mi.bigger().valid {
- return
- }
- if !mi.small.valid {
- mi.swapSmall()
- return
- }
- cmp := y.CompareKeys(mi.small.key, mi.bigger().key)
- switch {
- case cmp == 0: // Both the keys are equal.
- // In case of same keys, move the right iterator ahead.
- mi.right.next()
- if &mi.right == mi.small {
- mi.swapSmall()
- }
- return
- case cmp < 0: // Small is less than bigger().
- if mi.reverse {
- mi.swapSmall()
- } else { //nolint:staticcheck
- // we don't need to do anything. Small already points to the smallest.
- }
- return
- default: // bigger() is less than small.
- if mi.reverse {
- // Do nothing since we're iterating in reverse. Small currently points to
- // the bigger key and that's okay in reverse iteration.
- } else {
- mi.swapSmall()
- }
- return
- }
- }
- func (mi *MergeIterator) bigger() *node {
- if mi.small == &mi.left {
- return &mi.right
- }
- return &mi.left
- }
- func (mi *MergeIterator) swapSmall() {
- if mi.small == &mi.left {
- mi.small = &mi.right
- return
- }
- if mi.small == &mi.right {
- mi.small = &mi.left
- return
- }
- }
- // Next returns the next element. If it is the same as the current key, ignore it.
- func (mi *MergeIterator) Next() {
- for mi.Valid() {
- if !bytes.Equal(mi.small.key, mi.curKey) {
- break
- }
- mi.small.next()
- mi.fix()
- }
- mi.setCurrent()
- }
- func (mi *MergeIterator) setCurrent() {
- mi.curKey = append(mi.curKey[:0], mi.small.key...)
- }
- // Rewind seeks to first element (or last element for reverse iterator).
- func (mi *MergeIterator) Rewind() {
- mi.left.rewind()
- mi.right.rewind()
- mi.fix()
- mi.setCurrent()
- }
- // Seek brings us to element with key >= given key.
- func (mi *MergeIterator) Seek(key []byte) {
- mi.left.seek(key)
- mi.right.seek(key)
- mi.fix()
- mi.setCurrent()
- }
- // Valid returns whether the MergeIterator is at a valid element.
- func (mi *MergeIterator) Valid() bool {
- return mi.small.valid
- }
- // Key returns the key associated with the current iterator.
- func (mi *MergeIterator) Key() []byte {
- return mi.small.key
- }
- // Value returns the value associated with the iterator.
- func (mi *MergeIterator) Value() y.ValueStruct {
- return mi.small.iter.Value()
- }
- // Close implements y.Iterator.
- func (mi *MergeIterator) Close() error {
- err1 := mi.left.iter.Close()
- err2 := mi.right.iter.Close()
- if err1 != nil {
- return y.Wrap(err1, "MergeIterator")
- }
- return y.Wrap(err2, "MergeIterator")
- }
- // NewMergeIterator creates a merge iterator.
- func NewMergeIterator(iters []y.Iterator, reverse bool) y.Iterator {
- switch len(iters) {
- case 0:
- return nil
- case 1:
- return iters[0]
- case 2:
- mi := &MergeIterator{
- reverse: reverse,
- }
- mi.left.setIterator(iters[0])
- mi.right.setIterator(iters[1])
- // Assign left iterator randomly. This will be fixed when user calls rewind/seek.
- mi.small = &mi.left
- return mi
- }
- mid := len(iters) / 2
- return NewMergeIterator(
- []y.Iterator{
- NewMergeIterator(iters[:mid], reverse),
- NewMergeIterator(iters[mid:], reverse),
- }, reverse)
- }
|