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

Generated by: LCOV version 1.14