LCOV - code coverage report
Current view: top level - pebble/internal/keyspan - interleaving_iter.go (source / functions) Hit Total Coverage
Test: 2023-09-11 08:17Z 1efa535d - meta test only.lcov Lines: 551 615 89.6 %
Date: 2023-09-11 08:18:45 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2021 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package keyspan
       6             : 
       7             : import (
       8             :         "fmt"
       9             : 
      10             :         "github.com/cockroachdb/pebble/internal/base"
      11             :         "github.com/cockroachdb/pebble/internal/invariants"
      12             : )
      13             : 
      14             : // A SpanMask may be used to configure an interleaving iterator to skip point
      15             : // keys that fall within the bounds of some spans.
      16             : type SpanMask interface {
      17             :         // SpanChanged is invoked by an interleaving iterator whenever the current
      18             :         // span changes. As the iterator passes into or out of a Span, it invokes
      19             :         // SpanChanged, passing the new Span. When the iterator passes out of a
      20             :         // span's boundaries and is no longer covered by any span, SpanChanged is
      21             :         // invoked with a nil span.
      22             :         //
      23             :         // SpanChanged is invoked before SkipPoint, and callers may use SpanChanged
      24             :         // to recalculate state used by SkipPoint for masking.
      25             :         //
      26             :         // SpanChanged may be invoked consecutively with identical spans under some
      27             :         // circumstances, such as repeatedly absolutely positioning an iterator to
      28             :         // positions covered by the same span, or while changing directions.
      29             :         SpanChanged(*Span)
      30             :         // SkipPoint is invoked by the interleaving iterator whenever the iterator
      31             :         // encounters a point key covered by a Span. If SkipPoint returns true, the
      32             :         // interleaving iterator skips the point key and all larger keys with the
      33             :         // same prefix. This is used during range key iteration to skip over point
      34             :         // keys 'masked' by range keys.
      35             :         SkipPoint(userKey []byte) bool
      36             : }
      37             : 
      38             : // InterleavingIter combines an iterator over point keys with an iterator over
      39             : // key spans.
      40             : //
      41             : // Throughout Pebble, some keys apply at single discrete points within the user
      42             : // keyspace. Other keys apply over continuous spans of the user key space.
      43             : // Internally, iterators over point keys adhere to the base.InternalIterator
      44             : // interface, and iterators over spans adhere to the keyspan.FragmentIterator
      45             : // interface. The InterleavingIterator wraps a point iterator and span iterator,
      46             : // providing access to all the elements of both iterators.
      47             : //
      48             : // The InterleavingIterator implements the point base.InternalIterator
      49             : // interface. After any of the iterator's methods return a key, a caller may
      50             : // call Span to retrieve the span covering the returned key, if any.  A span is
      51             : // considered to 'cover' a returned key if the span's [start, end) bounds
      52             : // include the key's user key.
      53             : //
      54             : // In addition to tracking the current covering span, InterleavingIter returns a
      55             : // special InternalKey at span start boundaries. Start boundaries are surfaced
      56             : // as a synthetic span marker: an InternalKey with the boundary as the user key,
      57             : // the infinite sequence number and a key kind selected from an arbitrary key
      58             : // the infinite sequence number and an arbitrary contained key's kind. Since
      59             : // which of the Span's key's kind is surfaced is undefined, the caller should
      60             : // not use the InternalKey's kind. The caller should only rely on the `Span`
      61             : // method for retrieving information about spanning keys. The interleaved
      62             : // synthetic keys have the infinite sequence number so that they're interleaved
      63             : // before any point keys with the same user key when iterating forward and after
      64             : // when iterating backward.
      65             : //
      66             : // Interleaving the synthetic start key boundaries at the maximum sequence
      67             : // number provides an opportunity for the higher-level, public Iterator to
      68             : // observe the Span, even if no live points keys exist within the boudns of the
      69             : // Span.
      70             : //
      71             : // When returning a synthetic marker key for a start boundary, InterleavingIter
      72             : // will truncate the span's start bound to the SeekGE or SeekPrefixGE search
      73             : // key. For example, a SeekGE("d") that finds a span [a, z) may return a
      74             : // synthetic span marker key `d#72057594037927935,21`.
      75             : //
      76             : // If bounds have been applied to the iterator through SetBounds,
      77             : // InterleavingIter will truncate the bounds of spans returned through Span to
      78             : // the set bounds. The bounds returned through Span are not truncated by a
      79             : // SeekGE or SeekPrefixGE search key. Consider, for example SetBounds('c', 'e'),
      80             : // with an iterator containing the Span [a,z):
      81             : //
      82             : //      First()     = `c#72057594037927935,21`        Span() = [c,e)
      83             : //      SeekGE('d') = `d#72057594037927935,21`        Span() = [c,e)
      84             : //
      85             : // InterleavedIter does not interleave synthetic markers for spans that do not
      86             : // contain any keys.
      87             : //
      88             : // # SpanMask
      89             : //
      90             : // InterelavingIter takes a SpanMask parameter that may be used to configure the
      91             : // behavior of the iterator. See the documentation on the SpanMask type.
      92             : //
      93             : // All spans containing keys are exposed during iteration.
      94             : type InterleavingIter struct {
      95             :         cmp         base.Compare
      96             :         comparer    *base.Comparer
      97             :         pointIter   base.InternalIterator
      98             :         keyspanIter FragmentIterator
      99             :         mask        SpanMask
     100             : 
     101             :         // lower and upper hold the iteration bounds set through SetBounds.
     102             :         lower, upper []byte
     103             :         // keyBuf is used to copy SeekGE or SeekPrefixGE arguments when they're used
     104             :         // to truncate a span. The byte slices backing a SeekGE/SeekPrefixGE search
     105             :         // keys can come directly from the end user, so they're copied into keyBuf
     106             :         // to ensure key stability.
     107             :         keyBuf []byte
     108             :         // nextPrefixBuf is used during SeekPrefixGE calls to store the truncated
     109             :         // upper bound of the returned spans. SeekPrefixGE truncates the returned
     110             :         // spans to an upper bound of the seeked prefix's immediate successor.
     111             :         nextPrefixBuf []byte
     112             :         pointKey      *base.InternalKey
     113             :         pointVal      base.LazyValue
     114             :         // prefix records the iterator's current prefix if the iterator is in prefix
     115             :         // mode. During prefix mode, Pebble will truncate spans to the next prefix.
     116             :         // If the iterator subsequently leaves prefix mode, the existing span cached
     117             :         // in i.span must be invalidated because its bounds do not reflect the
     118             :         // original span's true bounds.
     119             :         prefix []byte
     120             :         // span holds the span at the keyspanIter's current position. If the span is
     121             :         // wholly contained within the iterator bounds, this span is directly
     122             :         // returned to the iterator consumer through Span(). If either bound needed
     123             :         // to be truncated to the iterator bounds, then truncated is set to true and
     124             :         // Span() must return a pointer to truncatedSpan.
     125             :         span *Span
     126             :         // spanMarker holds the synthetic key that is returned when the iterator
     127             :         // passes over a key span's start bound.
     128             :         spanMarker base.InternalKey
     129             :         // truncated indicates whether or not the span at the current position
     130             :         // needed to be truncated. If it did, truncatedSpan holds the truncated
     131             :         // span that should be returned.
     132             :         truncatedSpan Span
     133             :         truncated     bool
     134             : 
     135             :         // Keeping all of the bools/uint8s together reduces the sizeof the struct.
     136             : 
     137             :         // pos encodes the current position of the iterator: exhausted, on the point
     138             :         // key, on a keyspan start, or on a keyspan end.
     139             :         pos interleavePos
     140             :         // withinSpan indicates whether the iterator is currently positioned within
     141             :         // the bounds of the current span (i.span). withinSpan must be updated
     142             :         // whenever the interleaving iterator's position enters or exits the bounds
     143             :         // of a span.
     144             :         withinSpan bool
     145             :         // spanMarkerTruncated is set by SeekGE/SeekPrefixGE calls that truncate a
     146             :         // span's start bound marker to the search key. It's returned to false on
     147             :         // the next repositioning of the keyspan iterator.
     148             :         spanMarkerTruncated bool
     149             :         // maskSpanChangedCalled records whether or not the last call to
     150             :         // SpanMask.SpanChanged provided the current span (i.span) or not.
     151             :         maskSpanChangedCalled bool
     152             :         // dir indicates the direction of iteration: forward (+1) or backward (-1)
     153             :         dir int8
     154             : }
     155             : 
     156             : // interleavePos indicates the iterator's current position. Note that both
     157             : // keyspanStart and keyspanEnd positions correspond to their user key boundaries
     158             : // with maximal sequence numbers. This means in the forward direction
     159             : // posKeyspanStart and posKeyspanEnd are always interleaved before a posPointKey
     160             : // with the same user key.
     161             : type interleavePos int8
     162             : 
     163             : const (
     164             :         posUninitialized interleavePos = iota
     165             :         posExhausted
     166             :         posPointKey
     167             :         posKeyspanStart
     168             :         posKeyspanEnd
     169             : )
     170             : 
     171             : // Assert that *InterleavingIter implements the InternalIterator interface.
     172             : var _ base.InternalIterator = &InterleavingIter{}
     173             : 
     174             : // InterleavingIterOpts holds options configuring the behavior of a
     175             : // InterleavingIter.
     176             : type InterleavingIterOpts struct {
     177             :         Mask                   SpanMask
     178             :         LowerBound, UpperBound []byte
     179             : }
     180             : 
     181             : // Init initializes the InterleavingIter to interleave point keys from pointIter
     182             : // with key spans from keyspanIter.
     183             : //
     184             : // The point iterator must already have the bounds provided on opts. Init does
     185             : // not propagate the bounds down the iterator stack.
     186             : func (i *InterleavingIter) Init(
     187             :         comparer *base.Comparer,
     188             :         pointIter base.InternalIterator,
     189             :         keyspanIter FragmentIterator,
     190             :         opts InterleavingIterOpts,
     191           1 : ) {
     192           1 :         *i = InterleavingIter{
     193           1 :                 cmp:         comparer.Compare,
     194           1 :                 comparer:    comparer,
     195           1 :                 pointIter:   pointIter,
     196           1 :                 keyspanIter: keyspanIter,
     197           1 :                 mask:        opts.Mask,
     198           1 :                 lower:       opts.LowerBound,
     199           1 :                 upper:       opts.UpperBound,
     200           1 :         }
     201           1 : }
     202             : 
     203             : // InitSeekGE may be called after Init but before any positioning method.
     204             : // InitSeekGE initializes the current position of the point iterator and then
     205             : // performs a SeekGE on the keyspan iterator using the provided key. InitSeekGE
     206             : // returns whichever point or keyspan key is smaller. After InitSeekGE, the
     207             : // iterator is positioned and may be repositioned using relative positioning
     208             : // methods.
     209             : //
     210             : // This method is used specifically for lazily constructing combined iterators.
     211             : // It allows for seeding the iterator with the current position of the point
     212             : // iterator.
     213             : func (i *InterleavingIter) InitSeekGE(
     214             :         prefix, key []byte, pointKey *base.InternalKey, pointValue base.LazyValue,
     215           1 : ) (*base.InternalKey, base.LazyValue) {
     216           1 :         i.dir = +1
     217           1 :         i.clearMask()
     218           1 :         i.prefix = prefix
     219           1 :         i.pointKey, i.pointVal = pointKey, pointValue
     220           1 :         // NB: This keyspanSeekGE call will truncate the span to the seek key if
     221           1 :         // necessary. This truncation is important for cases where a switch to
     222           1 :         // combined iteration is made during a user-initiated SeekGE.
     223           1 :         i.keyspanSeekGE(key, prefix)
     224           1 :         i.computeSmallestPos()
     225           1 :         return i.yieldPosition(key, i.nextPos)
     226           1 : }
     227             : 
     228             : // InitSeekLT may be called after Init but before any positioning method.
     229             : // InitSeekLT initializes the current position of the point iterator and then
     230             : // performs a SeekLT on the keyspan iterator using the provided key. InitSeekLT
     231             : // returns whichever point or keyspan key is larger. After InitSeekLT, the
     232             : // iterator is positioned and may be repositioned using relative positioning
     233             : // methods.
     234             : //
     235             : // This method is used specifically for lazily constructing combined iterators.
     236             : // It allows for seeding the iterator with the current position of the point
     237             : // iterator.
     238             : func (i *InterleavingIter) InitSeekLT(
     239             :         key []byte, pointKey *base.InternalKey, pointValue base.LazyValue,
     240           1 : ) (*base.InternalKey, base.LazyValue) {
     241           1 :         i.dir = -1
     242           1 :         i.clearMask()
     243           1 :         i.pointKey, i.pointVal = pointKey, pointValue
     244           1 :         i.keyspanSeekLT(key)
     245           1 :         i.computeLargestPos()
     246           1 :         return i.yieldPosition(i.lower, i.prevPos)
     247           1 : }
     248             : 
     249             : // SeekGE implements (base.InternalIterator).SeekGE.
     250             : //
     251             : // If there exists a span with a start key ≤ the first matching point key,
     252             : // SeekGE will return a synthetic span marker key for the span. If this span's
     253             : // start key is less than key, the returned marker will be truncated to key.
     254             : // Note that this search-key truncation of the marker's key is not applied to
     255             : // the span returned by Span.
     256             : //
     257             : // NB: In accordance with the base.InternalIterator contract:
     258             : //
     259             : //      i.lower ≤ key
     260             : func (i *InterleavingIter) SeekGE(
     261             :         key []byte, flags base.SeekGEFlags,
     262           1 : ) (*base.InternalKey, base.LazyValue) {
     263           1 :         i.clearMask()
     264           1 :         i.disablePrefixMode()
     265           1 :         i.pointKey, i.pointVal = i.pointIter.SeekGE(key, flags)
     266           1 : 
     267           1 :         // We need to seek the keyspan iterator too. If the keyspan iterator was
     268           1 :         // already positioned at a span, we might be able to avoid the seek if the
     269           1 :         // seek key falls within the existing span's bounds.
     270           1 :         if i.span != nil && i.cmp(key, i.span.End) < 0 && i.cmp(key, i.span.Start) >= 0 {
     271           1 :                 // We're seeking within the existing span's bounds. We still might need
     272           1 :                 // truncate the span to the iterator's bounds.
     273           1 :                 i.checkForwardBound()
     274           1 :                 i.savedKeyspan()
     275           1 :         } else {
     276           1 :                 i.keyspanSeekGE(key, nil /* prefix */)
     277           1 :         }
     278             : 
     279           1 :         i.dir = +1
     280           1 :         i.computeSmallestPos()
     281           1 :         return i.yieldPosition(key, i.nextPos)
     282             : }
     283             : 
     284             : // SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
     285             : //
     286             : // If there exists a span with a start key ≤ the first matching point key,
     287             : // SeekPrefixGE will return a synthetic span marker key for the span. If this
     288             : // span's start key is less than key, the returned marker will be truncated to
     289             : // key. Note that this search-key truncation of the marker's key is not applied
     290             : // to the span returned by Span.
     291             : //
     292             : // NB: In accordance with the base.InternalIterator contract:
     293             : //
     294             : //      i.lower ≤ key
     295             : func (i *InterleavingIter) SeekPrefixGE(
     296             :         prefix, key []byte, flags base.SeekGEFlags,
     297           1 : ) (*base.InternalKey, base.LazyValue) {
     298           1 :         i.clearMask()
     299           1 :         i.prefix = prefix
     300           1 :         i.pointKey, i.pointVal = i.pointIter.SeekPrefixGE(prefix, key, flags)
     301           1 : 
     302           1 :         // We need to seek the keyspan iterator too. If the keyspan iterator was
     303           1 :         // already positioned at a span, we might be able to avoid the seek if the
     304           1 :         // entire seek prefix key falls within the existing span's bounds.
     305           1 :         //
     306           1 :         // During a SeekPrefixGE, Pebble defragments range keys within the bounds of
     307           1 :         // the prefix. For example, a SeekPrefixGE('c', 'c@8') must defragment the
     308           1 :         // any overlapping range keys within the bounds of [c,c\00).
     309           1 :         //
     310           1 :         // If range keys are fragmented within a prefix (eg, because a version
     311           1 :         // within a prefix was chosen as an sstable boundary), then it's possible
     312           1 :         // the seek key falls into the current i.span, but the current i.span does
     313           1 :         // not wholly cover the seek prefix.
     314           1 :         //
     315           1 :         // For example, a SeekPrefixGE('d@5') may only defragment a range key to
     316           1 :         // the bounds of [c@2,e). A subsequent SeekPrefixGE('c@0') must re-seek the
     317           1 :         // keyspan iterator, because although 'c@0' is contained within [c@2,e), the
     318           1 :         // full span of the prefix is not.
     319           1 :         //
     320           1 :         // Similarly, a SeekPrefixGE('a@3') may only defragment a range key to the
     321           1 :         // bounds [a,c@8). A subsequent SeekPrefixGE('c@10') must re-seek the
     322           1 :         // keyspan iterator, because although 'c@10' is contained within [a,c@8),
     323           1 :         // the full span of the prefix is not.
     324           1 :         seekKeyspanIter := true
     325           1 :         if i.span != nil && i.cmp(prefix, i.span.Start) >= 0 {
     326           1 :                 if ei := i.comparer.Split(i.span.End); i.cmp(prefix, i.span.End[:ei]) < 0 {
     327           1 :                         // We're seeking within the existing span's bounds. We still might need
     328           1 :                         // truncate the span to the iterator's bounds.
     329           1 :                         i.checkForwardBound()
     330           1 :                         i.savedKeyspan()
     331           1 :                         seekKeyspanIter = false
     332           1 :                 }
     333             :         }
     334           1 :         if seekKeyspanIter {
     335           1 :                 i.keyspanSeekGE(key, prefix)
     336           1 :         }
     337             : 
     338           1 :         i.dir = +1
     339           1 :         i.computeSmallestPos()
     340           1 :         return i.yieldPosition(key, i.nextPos)
     341             : }
     342             : 
     343             : // SeekLT implements (base.InternalIterator).SeekLT.
     344             : func (i *InterleavingIter) SeekLT(
     345             :         key []byte, flags base.SeekLTFlags,
     346           1 : ) (*base.InternalKey, base.LazyValue) {
     347           1 :         i.clearMask()
     348           1 :         i.disablePrefixMode()
     349           1 :         i.pointKey, i.pointVal = i.pointIter.SeekLT(key, flags)
     350           1 : 
     351           1 :         // We need to seek the keyspan iterator too. If the keyspan iterator was
     352           1 :         // already positioned at a span, we might be able to avoid the seek if the
     353           1 :         // seek key falls within the existing span's bounds.
     354           1 :         if i.span != nil && i.cmp(key, i.span.Start) > 0 && i.cmp(key, i.span.End) < 0 {
     355           1 :                 // We're seeking within the existing span's bounds. We still might need
     356           1 :                 // truncate the span to the iterator's bounds.
     357           1 :                 i.checkBackwardBound()
     358           1 :                 // The span's start key is still not guaranteed to be less than key,
     359           1 :                 // because of the bounds enforcement. Consider the following example:
     360           1 :                 //
     361           1 :                 // Bounds are set to [d,e). The user performs a SeekLT(d). The
     362           1 :                 // FragmentIterator.SeekLT lands on a span [b,f). This span has a start
     363           1 :                 // key less than d, as expected. Above, checkBackwardBound truncates the
     364           1 :                 // span to match the iterator's current bounds, modifying the span to
     365           1 :                 // [d,e), which does not overlap the search space of [-∞, d).
     366           1 :                 //
     367           1 :                 // This problem is a consequence of the SeekLT's exclusive search key
     368           1 :                 // and the fact that we don't perform bounds truncation at every leaf
     369           1 :                 // iterator.
     370           1 :                 if i.span != nil && i.truncated && i.cmp(i.truncatedSpan.Start, key) >= 0 {
     371           1 :                         i.span = nil
     372           1 :                 }
     373           1 :                 i.savedKeyspan()
     374           1 :         } else {
     375           1 :                 i.keyspanSeekLT(key)
     376           1 :         }
     377             : 
     378           1 :         i.dir = -1
     379           1 :         i.computeLargestPos()
     380           1 :         return i.yieldPosition(i.lower, i.prevPos)
     381             : }
     382             : 
     383             : // First implements (base.InternalIterator).First.
     384           1 : func (i *InterleavingIter) First() (*base.InternalKey, base.LazyValue) {
     385           1 :         i.clearMask()
     386           1 :         i.disablePrefixMode()
     387           1 :         i.pointKey, i.pointVal = i.pointIter.First()
     388           1 :         i.span = i.keyspanIter.First()
     389           1 :         i.checkForwardBound()
     390           1 :         i.savedKeyspan()
     391           1 :         i.dir = +1
     392           1 :         i.computeSmallestPos()
     393           1 :         return i.yieldPosition(i.lower, i.nextPos)
     394           1 : }
     395             : 
     396             : // Last implements (base.InternalIterator).Last.
     397           1 : func (i *InterleavingIter) Last() (*base.InternalKey, base.LazyValue) {
     398           1 :         i.clearMask()
     399           1 :         i.disablePrefixMode()
     400           1 :         i.pointKey, i.pointVal = i.pointIter.Last()
     401           1 :         i.span = i.keyspanIter.Last()
     402           1 :         i.checkBackwardBound()
     403           1 :         i.savedKeyspan()
     404           1 :         i.dir = -1
     405           1 :         i.computeLargestPos()
     406           1 :         return i.yieldPosition(i.lower, i.prevPos)
     407           1 : }
     408             : 
     409             : // Next implements (base.InternalIterator).Next.
     410           1 : func (i *InterleavingIter) Next() (*base.InternalKey, base.LazyValue) {
     411           1 :         if i.dir == -1 {
     412           1 :                 // Switching directions.
     413           1 :                 i.dir = +1
     414           1 : 
     415           1 :                 if i.mask != nil {
     416           1 :                         // Clear the mask while we reposition the point iterator. While
     417           1 :                         // switching directions, we may move the point iterator outside of
     418           1 :                         // i.span's bounds.
     419           1 :                         i.clearMask()
     420           1 :                 }
     421             : 
     422             :                 // When switching directions, iterator state corresponding to the
     423             :                 // current iterator position (as indicated by i.pos) is already correct.
     424             :                 // However any state that has yet to be interleaved describes a position
     425             :                 // behind the current iterator position and needs to be updated to
     426             :                 // describe the position ahead of the current iterator position.
     427           1 :                 switch i.pos {
     428           0 :                 case posExhausted:
     429             :                         // Nothing to do. The below nextPos call will move both the point
     430             :                         // key and span to their next positions and return
     431             :                         // MIN(point,s.Start).
     432           1 :                 case posPointKey:
     433           1 :                         // If we're currently on a point key, the below nextPos will
     434           1 :                         // correctly Next the point key iterator to the next point key.
     435           1 :                         // Do we need to move the span forwards? If the current span lies
     436           1 :                         // entirely behind the current key (!i.withinSpan), then we
     437           1 :                         // need to move it to the first span in the forward direction.
     438           1 :                         if !i.withinSpan {
     439           1 :                                 i.span = i.keyspanIter.Next()
     440           1 :                                 i.checkForwardBound()
     441           1 :                                 i.savedKeyspan()
     442           1 :                         }
     443           1 :                 case posKeyspanStart:
     444           1 :                         i.withinSpan = true
     445           1 :                         // Since we're positioned on a Span, the pointIter is positioned
     446           1 :                         // entirely behind the current iterator position. Reposition it
     447           1 :                         // ahead of the current iterator position.
     448           1 :                         i.pointKey, i.pointVal = i.pointIter.Next()
     449           0 :                 case posKeyspanEnd:
     450           0 :                         // Since we're positioned on a Span, the pointIter is positioned
     451           0 :                         // entirely behind of the current iterator position. Reposition it
     452           0 :                         // ahead the current iterator position.
     453           0 :                         i.pointKey, i.pointVal = i.pointIter.Next()
     454             :                 }
     455             :                 // Fallthrough to calling i.nextPos.
     456             :         }
     457           1 :         i.nextPos()
     458           1 :         return i.yieldPosition(i.lower, i.nextPos)
     459             : }
     460             : 
     461             : // NextPrefix implements (base.InternalIterator).NextPrefix.
     462           1 : func (i *InterleavingIter) NextPrefix(succKey []byte) (*base.InternalKey, base.LazyValue) {
     463           1 :         if i.dir == -1 {
     464           0 :                 panic("pebble: cannot switch directions with NextPrefix")
     465             :         }
     466             : 
     467           1 :         switch i.pos {
     468           0 :         case posExhausted:
     469           0 :                 return nil, base.LazyValue{}
     470           1 :         case posPointKey:
     471           1 :                 i.pointKey, i.pointVal = i.pointIter.NextPrefix(succKey)
     472           1 :                 if i.withinSpan {
     473           1 :                         if i.pointKey == nil || i.cmp(i.span.End, i.pointKey.UserKey) <= 0 {
     474           1 :                                 i.pos = posKeyspanEnd
     475           1 :                         } else {
     476           1 :                                 i.pos = posPointKey
     477           1 :                         }
     478           1 :                 } else {
     479           1 :                         i.computeSmallestPos()
     480           1 :                 }
     481           0 :         case posKeyspanStart, posKeyspanEnd:
     482           0 :                 i.nextPos()
     483             :         }
     484           1 :         return i.yieldPosition(i.lower, i.nextPos)
     485             : }
     486             : 
     487             : // Prev implements (base.InternalIterator).Prev.
     488           1 : func (i *InterleavingIter) Prev() (*base.InternalKey, base.LazyValue) {
     489           1 :         if i.dir == +1 {
     490           1 :                 // Switching directions.
     491           1 :                 i.dir = -1
     492           1 : 
     493           1 :                 if i.mask != nil {
     494           1 :                         // Clear the mask while we reposition the point iterator. While
     495           1 :                         // switching directions, we may move the point iterator outside of
     496           1 :                         // i.span's bounds.
     497           1 :                         i.clearMask()
     498           1 :                 }
     499             : 
     500             :                 // When switching directions, iterator state corresponding to the
     501             :                 // current iterator position (as indicated by i.pos) is already correct.
     502             :                 // However any state that has yet to be interleaved describes a position
     503             :                 // ahead of the current iterator position and needs to be updated to
     504             :                 // describe the position behind the current iterator position.
     505           1 :                 switch i.pos {
     506           0 :                 case posExhausted:
     507             :                         // Nothing to do. The below prevPos call will move both the point
     508             :                         // key and span to previous positions and return MAX(point, s.End).
     509           1 :                 case posPointKey:
     510           1 :                         // If we're currently on a point key, the point iterator is in the
     511           1 :                         // right place and the call to prevPos will correctly Prev the point
     512           1 :                         // key iterator to the previous point key. Do we need to move the
     513           1 :                         // span backwards? If the current span lies entirely ahead of the
     514           1 :                         // current key (!i.withinSpan), then we need to move it to the first
     515           1 :                         // span in the reverse direction.
     516           1 :                         if !i.withinSpan {
     517           1 :                                 i.span = i.keyspanIter.Prev()
     518           1 :                                 i.checkBackwardBound()
     519           1 :                                 i.savedKeyspan()
     520           1 :                         }
     521           1 :                 case posKeyspanStart:
     522           1 :                         // Since we're positioned on a Span, the pointIter is positioned
     523           1 :                         // entirely ahead of the current iterator position. Reposition it
     524           1 :                         // behind the current iterator position.
     525           1 :                         i.pointKey, i.pointVal = i.pointIter.Prev()
     526           1 :                         // Without considering truncation of spans to seek keys, the keyspan
     527           1 :                         // iterator is already in the right place. But consider span [a, z)
     528           1 :                         // and this sequence of iterator calls:
     529           1 :                         //
     530           1 :                         //   SeekGE('c') = c.RANGEKEYSET#72057594037927935
     531           1 :                         //   Prev()      = a.RANGEKEYSET#72057594037927935
     532           1 :                         //
     533           1 :                         // If the current span's start key was last surfaced truncated due
     534           1 :                         // to a SeekGE or SeekPrefixGE call, then it's still relevant in the
     535           1 :                         // reverse direction with an untruncated start key.
     536           1 :                         if i.spanMarkerTruncated {
     537           0 :                                 // When we fallthrough to calling prevPos, we want to move to
     538           0 :                                 // MAX(point, span.Start). We cheat here by claiming we're
     539           0 :                                 // currently on the end boundary, so that we'll move on to the
     540           0 :                                 // untruncated start key if necessary.
     541           0 :                                 i.pos = posKeyspanEnd
     542           0 :                         }
     543           0 :                 case posKeyspanEnd:
     544           0 :                         // Since we're positioned on a Span, the pointIter is positioned
     545           0 :                         // entirely ahead of the current iterator position. Reposition it
     546           0 :                         // behind the current iterator position.
     547           0 :                         i.pointKey, i.pointVal = i.pointIter.Prev()
     548             :                 }
     549             : 
     550           1 :                 if i.spanMarkerTruncated {
     551           1 :                         // Save the keyspan again to clear truncation.
     552           1 :                         i.savedKeyspan()
     553           1 :                 }
     554             :                 // Fallthrough to calling i.prevPos.
     555             :         }
     556           1 :         i.prevPos()
     557           1 :         return i.yieldPosition(i.lower, i.prevPos)
     558             : }
     559             : 
     560             : // computeSmallestPos sets i.{pos,withinSpan} to:
     561             : //
     562             : //      MIN(i.pointKey, i.span.Start)
     563           1 : func (i *InterleavingIter) computeSmallestPos() {
     564           1 :         if i.span != nil && (i.pointKey == nil || i.cmp(i.startKey(), i.pointKey.UserKey) <= 0) {
     565           1 :                 i.withinSpan = true
     566           1 :                 i.pos = posKeyspanStart
     567           1 :                 return
     568           1 :         }
     569           1 :         i.withinSpan = false
     570           1 :         if i.pointKey != nil {
     571           1 :                 i.pos = posPointKey
     572           1 :                 return
     573           1 :         }
     574           1 :         i.pos = posExhausted
     575             : }
     576             : 
     577             : // computeLargestPos sets i.{pos,withinSpan} to:
     578             : //
     579             : //      MAX(i.pointKey, i.span.End)
     580           1 : func (i *InterleavingIter) computeLargestPos() {
     581           1 :         if i.span != nil && (i.pointKey == nil || i.cmp(i.span.End, i.pointKey.UserKey) > 0) {
     582           1 :                 i.withinSpan = true
     583           1 :                 i.pos = posKeyspanEnd
     584           1 :                 return
     585           1 :         }
     586           1 :         i.withinSpan = false
     587           1 :         if i.pointKey != nil {
     588           1 :                 i.pos = posPointKey
     589           1 :                 return
     590           1 :         }
     591           1 :         i.pos = posExhausted
     592             : }
     593             : 
     594             : // nextPos advances the iterator one position in the forward direction.
     595           1 : func (i *InterleavingIter) nextPos() {
     596           1 :         switch i.pos {
     597           0 :         case posExhausted:
     598           0 :                 i.pointKey, i.pointVal = i.pointIter.Next()
     599           0 :                 i.span = i.keyspanIter.Next()
     600           0 :                 i.checkForwardBound()
     601           0 :                 i.savedKeyspan()
     602           0 :                 i.computeSmallestPos()
     603           1 :         case posPointKey:
     604           1 :                 i.pointKey, i.pointVal = i.pointIter.Next()
     605           1 :                 // If we're not currently within the span, we want to chose the
     606           1 :                 // MIN(pointKey,span.Start), which is exactly the calculation performed
     607           1 :                 // by computeSmallestPos.
     608           1 :                 if !i.withinSpan {
     609           1 :                         i.computeSmallestPos()
     610           1 :                         return
     611           1 :                 }
     612             :                 // i.withinSpan=true
     613             :                 // Since we previously were within the span, we want to choose the
     614             :                 // MIN(pointKey,span.End).
     615           1 :                 switch {
     616           0 :                 case i.span == nil:
     617           0 :                         panic("i.withinSpan=true and i.span=nil")
     618           1 :                 case i.pointKey == nil:
     619           1 :                         // Since i.withinSpan=true, we step onto the end boundary of the
     620           1 :                         // keyspan.
     621           1 :                         i.pos = posKeyspanEnd
     622           1 :                 default:
     623           1 :                         // i.withinSpan && i.pointKey != nil && i.span != nil
     624           1 :                         if i.cmp(i.span.End, i.pointKey.UserKey) <= 0 {
     625           1 :                                 i.pos = posKeyspanEnd
     626           1 :                         } else {
     627           1 :                                 i.pos = posPointKey
     628           1 :                         }
     629             :                 }
     630           1 :         case posKeyspanStart:
     631           1 :                 // Either a point key or the span's end key comes next.
     632           1 :                 if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.End) < 0 {
     633           1 :                         i.pos = posPointKey
     634           1 :                 } else {
     635           1 :                         i.pos = posKeyspanEnd
     636           1 :                 }
     637           1 :         case posKeyspanEnd:
     638           1 :                 i.span = i.keyspanIter.Next()
     639           1 :                 i.checkForwardBound()
     640           1 :                 i.savedKeyspan()
     641           1 :                 i.computeSmallestPos()
     642           0 :         default:
     643           0 :                 panic(fmt.Sprintf("unexpected pos=%d\n", i.pos))
     644             :         }
     645             : }
     646             : 
     647             : // prevPos advances the iterator one position in the reverse direction.
     648           1 : func (i *InterleavingIter) prevPos() {
     649           1 :         switch i.pos {
     650           0 :         case posExhausted:
     651           0 :                 i.pointKey, i.pointVal = i.pointIter.Prev()
     652           0 :                 i.span = i.keyspanIter.Prev()
     653           0 :                 i.checkBackwardBound()
     654           0 :                 i.savedKeyspan()
     655           0 :                 i.computeLargestPos()
     656           1 :         case posPointKey:
     657           1 :                 i.pointKey, i.pointVal = i.pointIter.Prev()
     658           1 :                 // If we're not currently covered by the span, we want to chose the
     659           1 :                 // MAX(pointKey,span.End), which is exactly the calculation performed
     660           1 :                 // by computeLargestPos.
     661           1 :                 if !i.withinSpan {
     662           1 :                         i.computeLargestPos()
     663           1 :                         return
     664           1 :                 }
     665           1 :                 switch {
     666           0 :                 case i.span == nil:
     667           0 :                         panic("withinSpan=true, but i.span == nil")
     668           1 :                 case i.pointKey == nil:
     669           1 :                         i.pos = posKeyspanEnd
     670           1 :                 default:
     671           1 :                         // i.withinSpan && i.pointKey != nil && i.span != nil
     672           1 :                         if i.cmp(i.span.Start, i.pointKey.UserKey) > 0 {
     673           1 :                                 i.pos = posKeyspanStart
     674           1 :                         } else {
     675           1 :                                 i.pos = posPointKey
     676           1 :                         }
     677             :                 }
     678           1 :         case posKeyspanStart:
     679           1 :                 i.span = i.keyspanIter.Prev()
     680           1 :                 i.checkBackwardBound()
     681           1 :                 i.savedKeyspan()
     682           1 :                 i.computeLargestPos()
     683           1 :         case posKeyspanEnd:
     684           1 :                 // Either a point key or the span's start key is previous.
     685           1 :                 if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.Start) >= 0 {
     686           1 :                         i.pos = posPointKey
     687           1 :                 } else {
     688           1 :                         i.pos = posKeyspanStart
     689           1 :                 }
     690           0 :         default:
     691           0 :                 panic(fmt.Sprintf("unexpected pos=%d\n", i.pos))
     692             :         }
     693             : }
     694             : 
     695             : func (i *InterleavingIter) yieldPosition(
     696             :         lowerBound []byte, advance func(),
     697           1 : ) (*base.InternalKey, base.LazyValue) {
     698           1 :         // This loop returns the first visible position in the current iteration
     699           1 :         // direction. Some positions are not visible and skipped. For example, if
     700           1 :         // masking is enabled and the iterator is positioned over a masked point
     701           1 :         // key, this loop skips the position. If a span's start key should be
     702           1 :         // interleaved next, but the span is empty, the loop continues to the next
     703           1 :         // key. Currently, span end keys are also always skipped, and are used only
     704           1 :         // for maintaining internal state.
     705           1 :         for {
     706           1 :                 switch i.pos {
     707           1 :                 case posExhausted:
     708           1 :                         return i.yieldNil()
     709           1 :                 case posPointKey:
     710           1 :                         if i.pointKey == nil {
     711           0 :                                 panic("i.pointKey is nil")
     712             :                         }
     713             : 
     714           1 :                         if i.mask != nil {
     715           1 :                                 i.maybeUpdateMask()
     716           1 :                                 if i.withinSpan && i.mask.SkipPoint(i.pointKey.UserKey) {
     717           1 :                                         // The span covers the point key. If a SkipPoint hook is
     718           1 :                                         // configured, ask it if we should skip this point key.
     719           1 :                                         if i.prefix != nil {
     720           1 :                                                 // During prefix-iteration node, once a point is masked,
     721           1 :                                                 // all subsequent keys with the same prefix must also be
     722           1 :                                                 // masked according to the key ordering. We can stop and
     723           1 :                                                 // return nil.
     724           1 :                                                 //
     725           1 :                                                 // NB: The above is not just an optimization. During
     726           1 :                                                 // prefix-iteration mode, the internal iterator contract
     727           1 :                                                 // prohibits us from Next-ing beyond the first key
     728           1 :                                                 // beyond the iteration prefix. If we didn't already
     729           1 :                                                 // stop early, we would need to check if this masked
     730           1 :                                                 // point is already beyond the prefix.
     731           1 :                                                 return i.yieldNil()
     732           1 :                                         }
     733             :                                         // TODO(jackson): If we thread a base.Comparer through to
     734             :                                         // InterleavingIter so that we have access to
     735             :                                         // ImmediateSuccessor, we could use NextPrefix. We'd need to
     736             :                                         // tweak the SpanMask interface slightly.
     737             : 
     738             :                                         // Advance beyond the masked point key.
     739           1 :                                         advance()
     740           1 :                                         continue
     741             :                                 }
     742             :                         }
     743           1 :                         return i.yieldPointKey()
     744           1 :                 case posKeyspanEnd:
     745           1 :                         // Don't interleave end keys; just advance.
     746           1 :                         advance()
     747           1 :                         continue
     748           1 :                 case posKeyspanStart:
     749           1 :                         // Don't interleave an empty span.
     750           1 :                         if i.span.Empty() {
     751           1 :                                 advance()
     752           1 :                                 continue
     753             :                         }
     754           1 :                         return i.yieldSyntheticSpanMarker(lowerBound)
     755           0 :                 default:
     756           0 :                         panic(fmt.Sprintf("unexpected interleavePos=%d", i.pos))
     757             :                 }
     758             :         }
     759             : }
     760             : 
     761             : // keyspanSeekGE seeks the keyspan iterator to the first span covering a key ≥ k.
     762           1 : func (i *InterleavingIter) keyspanSeekGE(k []byte, prefix []byte) {
     763           1 :         i.span = i.keyspanIter.SeekGE(k)
     764           1 :         i.checkForwardBound()
     765           1 :         i.savedKeyspan()
     766           1 : }
     767             : 
     768             : // keyspanSeekLT seeks the keyspan iterator to the last span covering a key < k.
     769           1 : func (i *InterleavingIter) keyspanSeekLT(k []byte) {
     770           1 :         i.span = i.keyspanIter.SeekLT(k)
     771           1 :         i.checkBackwardBound()
     772           1 :         // The current span's start key is not guaranteed to be less than key,
     773           1 :         // because of the bounds enforcement. Consider the following example:
     774           1 :         //
     775           1 :         // Bounds are set to [d,e). The user performs a SeekLT(d). The
     776           1 :         // FragmentIterator.SeekLT lands on a span [b,f). This span has a start key
     777           1 :         // less than d, as expected. Above, checkBackwardBound truncates the span to
     778           1 :         // match the iterator's current bounds, modifying the span to [d,e), which
     779           1 :         // does not overlap the search space of [-∞, d).
     780           1 :         //
     781           1 :         // This problem is a consequence of the SeekLT's exclusive search key and
     782           1 :         // the fact that we don't perform bounds truncation at every leaf iterator.
     783           1 :         if i.span != nil && i.truncated && i.cmp(i.truncatedSpan.Start, k) >= 0 {
     784           1 :                 i.span = nil
     785           1 :         }
     786           1 :         i.savedKeyspan()
     787             : }
     788             : 
     789           1 : func (i *InterleavingIter) checkForwardBound() {
     790           1 :         i.truncated = false
     791           1 :         i.truncatedSpan = Span{}
     792           1 :         if i.span == nil {
     793           1 :                 return
     794           1 :         }
     795             :         // Check the upper bound if we have one.
     796           1 :         if i.upper != nil && i.cmp(i.span.Start, i.upper) >= 0 {
     797           0 :                 i.span = nil
     798           0 :                 return
     799           0 :         }
     800             : 
     801             :         // TODO(jackson): The key comparisons below truncate bounds whenever the
     802             :         // keyspan iterator is repositioned. We could perform this lazily, and do it
     803             :         // the first time the user actually asks for this span's bounds in
     804             :         // SpanBounds. This would reduce work in the case where there's no span
     805             :         // covering the point and the keyspan iterator is non-empty.
     806             : 
     807             :         // NB: These truncations don't require setting `keyspanMarkerTruncated`:
     808             :         // That flag only applies to truncated span marker keys.
     809           1 :         if i.lower != nil && i.cmp(i.span.Start, i.lower) < 0 {
     810           1 :                 i.truncated = true
     811           1 :                 i.truncatedSpan = *i.span
     812           1 :                 i.truncatedSpan.Start = i.lower
     813           1 :         }
     814           1 :         if i.upper != nil && i.cmp(i.upper, i.span.End) < 0 {
     815           1 :                 if !i.truncated {
     816           1 :                         i.truncated = true
     817           1 :                         i.truncatedSpan = *i.span
     818           1 :                 }
     819           1 :                 i.truncatedSpan.End = i.upper
     820             :         }
     821             :         // If this is a part of a SeekPrefixGE call, we may also need to truncate to
     822             :         // the prefix's bounds.
     823           1 :         if i.prefix != nil {
     824           1 :                 if !i.truncated {
     825           1 :                         i.truncated = true
     826           1 :                         i.truncatedSpan = *i.span
     827           1 :                 }
     828           1 :                 if i.cmp(i.prefix, i.truncatedSpan.Start) > 0 {
     829           1 :                         i.truncatedSpan.Start = i.prefix
     830           1 :                 }
     831           1 :                 i.nextPrefixBuf = i.comparer.ImmediateSuccessor(i.nextPrefixBuf[:0], i.prefix)
     832           1 :                 if i.truncated && i.cmp(i.nextPrefixBuf, i.truncatedSpan.End) < 0 {
     833           1 :                         i.truncatedSpan.End = i.nextPrefixBuf
     834           1 :                 }
     835             :         }
     836             : 
     837           1 :         if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) {
     838           1 :                 i.span = nil
     839           1 :         }
     840             : }
     841             : 
     842           1 : func (i *InterleavingIter) checkBackwardBound() {
     843           1 :         i.truncated = false
     844           1 :         i.truncatedSpan = Span{}
     845           1 :         if i.span == nil {
     846           1 :                 return
     847           1 :         }
     848             :         // Check the lower bound if we have one.
     849           1 :         if i.lower != nil && i.cmp(i.span.End, i.lower) <= 0 {
     850           0 :                 i.span = nil
     851           0 :                 return
     852           0 :         }
     853             : 
     854             :         // TODO(jackson): The key comparisons below truncate bounds whenever the
     855             :         // keyspan iterator is repositioned. We could perform this lazily, and do it
     856             :         // the first time the user actually asks for this span's bounds in
     857             :         // SpanBounds. This would reduce work in the case where there's no span
     858             :         // covering the point and the keyspan iterator is non-empty.
     859             : 
     860             :         // NB: These truncations don't require setting `keyspanMarkerTruncated`:
     861             :         // That flag only applies to truncated span marker keys.
     862           1 :         if i.lower != nil && i.cmp(i.span.Start, i.lower) < 0 {
     863           1 :                 i.truncated = true
     864           1 :                 i.truncatedSpan = *i.span
     865           1 :                 i.truncatedSpan.Start = i.lower
     866           1 :         }
     867           1 :         if i.upper != nil && i.cmp(i.upper, i.span.End) < 0 {
     868           1 :                 if !i.truncated {
     869           1 :                         i.truncated = true
     870           1 :                         i.truncatedSpan = *i.span
     871           1 :                 }
     872           1 :                 i.truncatedSpan.End = i.upper
     873             :         }
     874           1 :         if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) {
     875           1 :                 i.span = nil
     876           1 :         }
     877             : }
     878             : 
     879           1 : func (i *InterleavingIter) yieldNil() (*base.InternalKey, base.LazyValue) {
     880           1 :         i.withinSpan = false
     881           1 :         i.clearMask()
     882           1 :         return i.verify(nil, base.LazyValue{})
     883           1 : }
     884             : 
     885           1 : func (i *InterleavingIter) yieldPointKey() (*base.InternalKey, base.LazyValue) {
     886           1 :         return i.verify(i.pointKey, i.pointVal)
     887           1 : }
     888             : 
     889             : func (i *InterleavingIter) yieldSyntheticSpanMarker(
     890             :         lowerBound []byte,
     891           1 : ) (*base.InternalKey, base.LazyValue) {
     892           1 :         i.spanMarker.UserKey = i.startKey()
     893           1 :         i.spanMarker.Trailer = base.MakeTrailer(base.InternalKeySeqNumMax, i.span.Keys[0].Kind())
     894           1 : 
     895           1 :         // Truncate the key we return to our lower bound if we have one. Note that
     896           1 :         // we use the lowerBound function parameter, not i.lower. The lowerBound
     897           1 :         // argument is guaranteed to be ≥ i.lower. It may be equal to the SetBounds
     898           1 :         // lower bound, or it could come from a SeekGE or SeekPrefixGE search key.
     899           1 :         if lowerBound != nil && i.cmp(lowerBound, i.startKey()) > 0 {
     900           1 :                 // Truncating to the lower bound may violate the upper bound if
     901           1 :                 // lowerBound == i.upper. For example, a SeekGE(k) uses k as a lower
     902           1 :                 // bound for truncating a span. The span a-z will be truncated to [k,
     903           1 :                 // z). If i.upper == k, we'd mistakenly try to return a span [k, k), an
     904           1 :                 // invariant violation.
     905           1 :                 if i.comparer.Equal(lowerBound, i.upper) {
     906           1 :                         return i.yieldNil()
     907           1 :                 }
     908             : 
     909             :                 // If the lowerBound argument came from a SeekGE or SeekPrefixGE
     910             :                 // call, and it may be backed by a user-provided byte slice that is not
     911             :                 // guaranteed to be stable.
     912             :                 //
     913             :                 // If the lowerBound argument is the lower bound set by SetBounds,
     914             :                 // Pebble owns the slice's memory. However, consider two successive
     915             :                 // calls to SetBounds(). The second may overwrite the lower bound.
     916             :                 // Although the external contract requires a seek after a SetBounds,
     917             :                 // Pebble's tests don't always. For this reason and to simplify
     918             :                 // reasoning around lifetimes, always copy the bound into keyBuf when
     919             :                 // truncating.
     920           1 :                 i.keyBuf = append(i.keyBuf[:0], lowerBound...)
     921           1 :                 i.spanMarker.UserKey = i.keyBuf
     922           1 :                 i.spanMarkerTruncated = true
     923             :         }
     924           1 :         i.maybeUpdateMask()
     925           1 :         return i.verify(&i.spanMarker, base.LazyValue{})
     926             : }
     927             : 
     928           1 : func (i *InterleavingIter) disablePrefixMode() {
     929           1 :         if i.prefix != nil {
     930           1 :                 i.prefix = nil
     931           1 :                 // Clear the existing span. It may not hold the true end bound of the
     932           1 :                 // underlying span.
     933           1 :                 i.span = nil
     934           1 :         }
     935             : }
     936             : 
     937             : func (i *InterleavingIter) verify(
     938             :         k *base.InternalKey, v base.LazyValue,
     939           1 : ) (*base.InternalKey, base.LazyValue) {
     940           1 :         // Wrap the entire function body in the invariants build tag, so that
     941           1 :         // production builds elide this entire function.
     942           1 :         if invariants.Enabled {
     943           0 :                 switch {
     944           0 :                 case i.dir == -1 && i.spanMarkerTruncated:
     945           0 :                         panic("pebble: invariant violation: truncated span key in reverse iteration")
     946           0 :                 case k != nil && i.lower != nil && i.cmp(k.UserKey, i.lower) < 0:
     947           0 :                         panic("pebble: invariant violation: key < lower bound")
     948           0 :                 case k != nil && i.upper != nil && i.cmp(k.UserKey, i.upper) >= 0:
     949           0 :                         panic("pebble: invariant violation: key ≥ upper bound")
     950             :                 }
     951             :         }
     952           1 :         return k, v
     953             : }
     954             : 
     955           1 : func (i *InterleavingIter) savedKeyspan() {
     956           1 :         i.spanMarkerTruncated = false
     957           1 :         i.maskSpanChangedCalled = false
     958           1 : }
     959             : 
     960             : // updateMask updates the current mask, if a mask is configured and the mask
     961             : // hasn't been updated with the current keyspan yet.
     962           1 : func (i *InterleavingIter) maybeUpdateMask() {
     963           1 :         switch {
     964           1 :         case i.mask == nil, i.maskSpanChangedCalled:
     965           1 :                 return
     966           1 :         case !i.withinSpan || i.span.Empty():
     967           1 :                 i.clearMask()
     968           1 :         case i.truncated:
     969           1 :                 i.mask.SpanChanged(&i.truncatedSpan)
     970           1 :                 i.maskSpanChangedCalled = true
     971           1 :         default:
     972           1 :                 i.mask.SpanChanged(i.span)
     973           1 :                 i.maskSpanChangedCalled = true
     974             :         }
     975             : }
     976             : 
     977             : // clearMask clears the current mask, if a mask is configured and no mask should
     978             : // be active.
     979           1 : func (i *InterleavingIter) clearMask() {
     980           1 :         if i.mask != nil {
     981           1 :                 i.maskSpanChangedCalled = false
     982           1 :                 i.mask.SpanChanged(nil)
     983           1 :         }
     984             : }
     985             : 
     986           1 : func (i *InterleavingIter) startKey() []byte {
     987           1 :         if i.truncated {
     988           1 :                 return i.truncatedSpan.Start
     989           1 :         }
     990           1 :         return i.span.Start
     991             : }
     992             : 
     993             : // Span returns the span covering the last key returned, if any. A span key is
     994             : // considered to 'cover' a key if the key falls within the span's user key
     995             : // bounds. The returned span is owned by the InterleavingIter. The caller is
     996             : // responsible for copying if stability is required.
     997             : //
     998             : // Span will never return an invalid or empty span.
     999           1 : func (i *InterleavingIter) Span() *Span {
    1000           1 :         if !i.withinSpan || len(i.span.Keys) == 0 {
    1001           1 :                 return nil
    1002           1 :         } else if i.truncated {
    1003           1 :                 return &i.truncatedSpan
    1004           1 :         }
    1005           1 :         return i.span
    1006             : }
    1007             : 
    1008             : // SetBounds implements (base.InternalIterator).SetBounds.
    1009           1 : func (i *InterleavingIter) SetBounds(lower, upper []byte) {
    1010           1 :         i.lower, i.upper = lower, upper
    1011           1 :         i.pointIter.SetBounds(lower, upper)
    1012           1 :         i.Invalidate()
    1013           1 : }
    1014             : 
    1015             : // Invalidate invalidates the interleaving iterator's current position, clearing
    1016             : // its state. This prevents optimizations such as reusing the current span on
    1017             : // seek.
    1018           1 : func (i *InterleavingIter) Invalidate() {
    1019           1 :         i.span = nil
    1020           1 :         i.pointKey = nil
    1021           1 :         i.pointVal = base.LazyValue{}
    1022           1 : }
    1023             : 
    1024             : // Error implements (base.InternalIterator).Error.
    1025           1 : func (i *InterleavingIter) Error() error {
    1026           1 :         return firstError(i.pointIter.Error(), i.keyspanIter.Error())
    1027           1 : }
    1028             : 
    1029             : // Close implements (base.InternalIterator).Close.
    1030           1 : func (i *InterleavingIter) Close() error {
    1031           1 :         perr := i.pointIter.Close()
    1032           1 :         rerr := i.keyspanIter.Close()
    1033           1 :         return firstError(perr, rerr)
    1034           1 : }
    1035             : 
    1036             : // String implements (base.InternalIterator).String.
    1037           0 : func (i *InterleavingIter) String() string {
    1038           0 :         return fmt.Sprintf("keyspan-interleaving(%q)", i.pointIter.String())
    1039           0 : }
    1040             : 
    1041           1 : func firstError(err0, err1 error) error {
    1042           1 :         if err0 != nil {
    1043           0 :                 return err0
    1044           0 :         }
    1045           1 :         return err1
    1046             : }

Generated by: LCOV version 1.14