LCOV - code coverage report
Current view: top level - pebble/internal/arenaskl - iterator.go (source / functions) Hit Total Coverage
Test: 2024-12-13 08:17Z 924a6698 - tests + meta.lcov Lines: 142 155 91.6 %
Date: 2024-12-13 08:18:13 Functions: 0 0 -

          Line data    Source code
       1             : /*
       2             :  * Copyright 2017 Dgraph Labs, Inc. and Contributors
       3             :  * Modifications copyright (C) 2017 Andy Kimball and Contributors
       4             :  *
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : package arenaskl
      19             : 
      20             : import (
      21             :         "context"
      22             :         "sync"
      23             : 
      24             :         "github.com/cockroachdb/pebble/internal/base"
      25             :         "github.com/cockroachdb/pebble/internal/treeprinter"
      26             : )
      27             : 
      28             : type splice struct {
      29             :         prev *node
      30             :         next *node
      31             : }
      32             : 
      33           2 : func (s *splice) init(prev, next *node) {
      34           2 :         s.prev = prev
      35           2 :         s.next = next
      36           2 : }
      37             : 
      38             : // Iterator is an iterator over the skiplist object. Use Skiplist.NewIter
      39             : // to construct an iterator. The current state of the iterator can be cloned by
      40             : // simply value copying the struct. All iterator methods are thread-safe.
      41             : type Iterator struct {
      42             :         list  *Skiplist
      43             :         nd    *node
      44             :         kv    base.InternalKV
      45             :         lower []byte
      46             :         upper []byte
      47             :         // {lower|upper}Node are lazily populated with an arbitrary node that is
      48             :         // beyond the lower or upper bound respectively. Note the node is
      49             :         // "arbitrary" because it may not be the first node that exceeds the bound.
      50             :         // Concurrent insertions into the skiplist may introduce new nodes with keys
      51             :         // that exceed the bounds but are closer to the bounds than the current
      52             :         // values of [lower|upper]Node.
      53             :         //
      54             :         // Once populated, [lower|upper]Node may be used to detect when iteration
      55             :         // has reached a bound without performing a key comparison. This may be
      56             :         // beneficial when performing repeated SeekGEs with TrySeekUsingNext and an
      57             :         // upper bound set. Once the upper bound has been met, no additional key
      58             :         // comparisons are necessary.
      59             :         lowerNode *node
      60             :         upperNode *node
      61             : }
      62             : 
      63             : // Iterator implements the base.InternalIterator interface.
      64             : var _ base.InternalIterator = (*Iterator)(nil)
      65             : 
      66             : var iterPool = sync.Pool{
      67           2 :         New: func() interface{} {
      68           2 :                 return &Iterator{}
      69           2 :         },
      70             : }
      71             : 
      72             : // Close resets the iterator.
      73           2 : func (it *Iterator) Close() error {
      74           2 :         *it = Iterator{}
      75           2 :         iterPool.Put(it)
      76           2 :         return nil
      77           2 : }
      78             : 
      79           2 : func (it *Iterator) String() string {
      80           2 :         return "memtable"
      81           2 : }
      82             : 
      83             : // Error returns any accumulated error.
      84           2 : func (it *Iterator) Error() error {
      85           2 :         return nil
      86           2 : }
      87             : 
      88             : // SeekGE moves the iterator to the first entry whose key is greater than or
      89             : // equal to the given key. Returns the KV pair if the iterator is pointing at a
      90             : // valid entry, and nil otherwise. Note that SeekGE only checks the upper bound.
      91             : // It is up to the caller to ensure that key is greater than or equal to the
      92             : // lower bound.
      93           2 : func (it *Iterator) SeekGE(key []byte, flags base.SeekGEFlags) *base.InternalKV {
      94           2 :         if flags.TrySeekUsingNext() {
      95           2 :                 if it.nd == it.list.tail || it.nd == it.upperNode {
      96           2 :                         // Iterator is done.
      97           2 :                         return nil
      98           2 :                 }
      99           2 :                 less := it.list.cmp(it.kv.K.UserKey, key) < 0
     100           2 :                 // Arbitrary constant. By measuring the seek cost as a function of the
     101           2 :                 // number of elements in the skip list, and fitting to a model, we
     102           2 :                 // could adjust the number of nexts based on the current size of the
     103           2 :                 // skip list.
     104           2 :                 const numNexts = 5
     105           2 :                 kv := &it.kv
     106           2 :                 for i := 0; less && i < numNexts; i++ {
     107           2 :                         if kv = it.Next(); kv == nil {
     108           2 :                                 // Iterator is done.
     109           2 :                                 return nil
     110           2 :                         }
     111           2 :                         less = it.list.cmp(kv.K.UserKey, key) < 0
     112             :                 }
     113           2 :                 if !less {
     114           2 :                         return kv
     115           2 :                 }
     116             :         }
     117           2 :         _, it.nd, _ = it.seekForBaseSplice(key)
     118           2 :         if it.nd == it.list.tail || it.nd == it.upperNode {
     119           2 :                 return nil
     120           2 :         }
     121           2 :         it.decodeKey()
     122           2 :         if it.upper != nil && it.list.cmp(it.upper, it.kv.K.UserKey) <= 0 {
     123           2 :                 it.upperNode = it.nd
     124           2 :                 return nil
     125           2 :         }
     126           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     127           2 :         return &it.kv
     128             : }
     129             : 
     130             : // SeekPrefixGE moves the iterator to the first entry whose key is greater than
     131             : // or equal to the given key. This method is equivalent to SeekGE and is
     132             : // provided so that an arenaskl.Iterator implements the
     133             : // internal/base.InternalIterator interface.
     134           2 : func (it *Iterator) SeekPrefixGE(prefix, key []byte, flags base.SeekGEFlags) *base.InternalKV {
     135           2 :         return it.SeekGE(key, flags)
     136           2 : }
     137             : 
     138             : // SeekLT moves the iterator to the last entry whose key is less than the given
     139             : // key. Returns the KV pair if the iterator is pointing at a valid entry, and
     140             : // nil otherwise. Note that SeekLT only checks the lower bound. It is up to the
     141             : // caller to ensure that key is less than the upper bound.
     142           2 : func (it *Iterator) SeekLT(key []byte, flags base.SeekLTFlags) *base.InternalKV {
     143           2 :         // NB: the top-level Iterator has already adjusted key based on
     144           2 :         // the upper-bound.
     145           2 :         it.nd, _, _ = it.seekForBaseSplice(key)
     146           2 :         if it.nd == it.list.head || it.nd == it.lowerNode {
     147           2 :                 return nil
     148           2 :         }
     149           2 :         it.decodeKey()
     150           2 :         if it.lower != nil && it.list.cmp(it.lower, it.kv.K.UserKey) > 0 {
     151           2 :                 it.lowerNode = it.nd
     152           2 :                 return nil
     153           2 :         }
     154           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     155           2 :         return &it.kv
     156             : }
     157             : 
     158             : // First seeks position at the first entry in list. Returns the KV pair if the
     159             : // iterator is pointing at a valid entry, and nil otherwise. Note that First
     160             : // only checks the upper bound. It is up to the caller to ensure that key is
     161             : // greater than or equal to the lower bound (e.g. via a call to SeekGE(lower)).
     162           2 : func (it *Iterator) First() *base.InternalKV {
     163           2 :         it.nd = it.list.getNext(it.list.head, 0)
     164           2 :         if it.nd == it.list.tail || it.nd == it.upperNode {
     165           2 :                 return nil
     166           2 :         }
     167           2 :         it.decodeKey()
     168           2 :         if it.upper != nil && it.list.cmp(it.upper, it.kv.K.UserKey) <= 0 {
     169           2 :                 it.upperNode = it.nd
     170           2 :                 return nil
     171           2 :         }
     172           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     173           2 :         return &it.kv
     174             : }
     175             : 
     176             : // Last seeks position at the last entry in list. Returns the KV pair if the
     177             : // iterator is pointing at a valid entry, and nil otherwise. Note that Last only
     178             : // checks the lower bound. It is up to the caller to ensure that key is less
     179             : // than the upper bound (e.g. via a call to SeekLT(upper)).
     180           2 : func (it *Iterator) Last() *base.InternalKV {
     181           2 :         it.nd = it.list.getPrev(it.list.tail, 0)
     182           2 :         if it.nd == it.list.head || it.nd == it.lowerNode {
     183           2 :                 return nil
     184           2 :         }
     185           2 :         it.decodeKey()
     186           2 :         if it.lower != nil && it.list.cmp(it.lower, it.kv.K.UserKey) > 0 {
     187           0 :                 it.lowerNode = it.nd
     188           0 :                 return nil
     189           0 :         }
     190           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     191           2 :         return &it.kv
     192             : }
     193             : 
     194             : // Next advances to the next position. Returns the KV pair if the iterator is
     195             : // pointing at a valid entry, and nil otherwise.
     196             : // Note: flushIterator.Next mirrors the implementation of Iterator.Next
     197             : // due to performance. Keep the two in sync.
     198           2 : func (it *Iterator) Next() *base.InternalKV {
     199           2 :         it.nd = it.list.getNext(it.nd, 0)
     200           2 :         if it.nd == it.list.tail || it.nd == it.upperNode {
     201           2 :                 return nil
     202           2 :         }
     203           2 :         it.decodeKey()
     204           2 :         if it.upper != nil && it.list.cmp(it.upper, it.kv.K.UserKey) <= 0 {
     205           2 :                 it.upperNode = it.nd
     206           2 :                 return nil
     207           2 :         }
     208           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     209           2 :         return &it.kv
     210             : }
     211             : 
     212             : // NextPrefix advances to the next position with a new prefix. Returns the KV
     213             : // pair if the iterator is pointing at a valid entry and nil otherwise.
     214           2 : func (it *Iterator) NextPrefix(succKey []byte) *base.InternalKV {
     215           2 :         return it.SeekGE(succKey, base.SeekGEFlagsNone.EnableTrySeekUsingNext())
     216           2 : }
     217             : 
     218             : // Prev moves to the previous position. Returns the KV pair if the iterator is
     219             : // pointing at a valid entry and nil otherwise.
     220           2 : func (it *Iterator) Prev() *base.InternalKV {
     221           2 :         it.nd = it.list.getPrev(it.nd, 0)
     222           2 :         if it.nd == it.list.head || it.nd == it.lowerNode {
     223           2 :                 return nil
     224           2 :         }
     225           2 :         it.decodeKey()
     226           2 :         if it.lower != nil && it.list.cmp(it.lower, it.kv.K.UserKey) > 0 {
     227           2 :                 it.lowerNode = it.nd
     228           2 :                 return nil
     229           2 :         }
     230           2 :         it.kv.V = base.MakeInPlaceValue(it.value())
     231           2 :         return &it.kv
     232             : }
     233             : 
     234             : // value returns the value at the current position.
     235           2 : func (it *Iterator) value() []byte {
     236           2 :         return it.nd.getValue(it.list.arena)
     237           2 : }
     238             : 
     239             : // SetBounds sets the lower and upper bounds for the iterator. Note that the
     240             : // result of Next and Prev will be undefined until the iterator has been
     241             : // repositioned with SeekGE, SeekPrefixGE, SeekLT, First, or Last.
     242           2 : func (it *Iterator) SetBounds(lower, upper []byte) {
     243           2 :         it.lower = lower
     244           2 :         it.upper = upper
     245           2 :         it.lowerNode = nil
     246           2 :         it.upperNode = nil
     247           2 : }
     248             : 
     249             : // SetContext implements base.InternalIterator.
     250           0 : func (it *Iterator) SetContext(_ context.Context) {}
     251             : 
     252             : // DebugTree is part of the InternalIterator interface.
     253           0 : func (it *Iterator) DebugTree(tp treeprinter.Node) {
     254           0 :         tp.Childf("%T(%p)", it, it)
     255           0 : }
     256             : 
     257           2 : func (it *Iterator) decodeKey() {
     258           2 :         it.kv.K.UserKey = it.list.arena.getBytes(it.nd.keyOffset, it.nd.keySize)
     259           2 :         it.kv.K.Trailer = it.nd.keyTrailer
     260           2 : }
     261             : 
     262           2 : func (it *Iterator) seekForBaseSplice(key []byte) (prev, next *node, found bool) {
     263           2 :         ikey := base.MakeSearchKey(key)
     264           2 :         level := int(it.list.Height() - 1)
     265           2 : 
     266           2 :         prev = it.list.head
     267           2 :         for {
     268           2 :                 prev, next, found = it.list.findSpliceForLevel(ikey, level, prev)
     269           2 : 
     270           2 :                 if found {
     271           0 :                         if level != 0 {
     272           0 :                                 // next is pointing at the target node, but we need to find previous on
     273           0 :                                 // the bottom level.
     274           0 :                                 prev = it.list.getPrev(next, 0)
     275           0 :                         }
     276           0 :                         break
     277             :                 }
     278             : 
     279           2 :                 if level == 0 {
     280           2 :                         break
     281             :                 }
     282             : 
     283           2 :                 level--
     284             :         }
     285             : 
     286           2 :         return
     287             : }

Generated by: LCOV version 1.14