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

Generated by: LCOV version 1.14