LCOV - code coverage report
Current view: top level - pebble/internal/keyspan/keyspanimpl - merging_iter.go (source / functions) Hit Total Coverage
Test: 2024-08-11 08:16Z 791b3749 - meta test only.lcov Lines: 650 754 86.2 %
Date: 2024-08-11 08:17:17 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2022 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 keyspanimpl
       6             : 
       7             : import (
       8             :         "bytes"
       9             :         "cmp"
      10             :         "context"
      11             :         "fmt"
      12             :         "slices"
      13             : 
      14             :         "github.com/cockroachdb/pebble/internal/base"
      15             :         "github.com/cockroachdb/pebble/internal/invariants"
      16             :         "github.com/cockroachdb/pebble/internal/keyspan"
      17             :         "github.com/cockroachdb/pebble/internal/manifest"
      18             :         "github.com/cockroachdb/pebble/internal/treeprinter"
      19             : )
      20             : 
      21             : // TODO(jackson): Consider implementing an optimization to seek lower levels
      22             : // past higher levels' RANGEKEYDELs. This would be analaogous to the
      23             : // optimization pebble.mergingIter performs for RANGEDELs during point key
      24             : // seeks. It may not be worth it, because range keys are rare and cascading
      25             : // seeks would require introducing key comparisons to switchTo{Min,Max}Heap
      26             : // where there currently are none.
      27             : 
      28             : // MergingIter merges spans across levels of the LSM, exposing an iterator over
      29             : // spans that yields sets of spans fragmented at unique user key boundaries.
      30             : //
      31             : // A MergingIter is initialized with an arbitrary number of child iterators over
      32             : // fragmented spans. Each child iterator exposes fragmented key spans, such that
      33             : // overlapping keys are surfaced in a single Span. Key spans from one child
      34             : // iterator may overlap key spans from another child iterator arbitrarily.
      35             : //
      36             : // The spans combined by MergingIter will return spans with keys sorted by
      37             : // trailer descending. If the MergingIter is configured with a Transformer, it's
      38             : // permitted to modify the ordering of the spans' keys returned by MergingIter.
      39             : //
      40             : // # Algorithm
      41             : //
      42             : // The merging iterator wraps child iterators, merging and fragmenting spans
      43             : // across levels. The high-level algorithm is:
      44             : //
      45             : //  1. Initialize the heap with bound keys from child iterators' spans.
      46             : //  2. Find the next [or previous] two unique user keys' from bounds.
      47             : //  3. Consider the span formed between the two unique user keys a candidate
      48             : //     span.
      49             : //  4. Determine if any of the child iterators' spans overlap the candidate
      50             : //     span.
      51             : //     4a. If any of the child iterator's current bounds are end keys
      52             : //     (during forward iteration) or start keys (during reverse
      53             : //     iteration), then all the spans with that bound overlap the
      54             : //     candidate span.
      55             : //     4b. Apply the configured transform, which may remove keys.
      56             : //     4c. If no spans overlap, forget the smallest (forward iteration)
      57             : //     or largest (reverse iteration) unique user key and advance
      58             : //     the iterators to the next unique user key. Start again from 3.
      59             : //
      60             : // # Detailed algorithm
      61             : //
      62             : // Each level (i0, i1, ...) has a user-provided input FragmentIterator. The
      63             : // merging iterator steps through individual boundaries of the underlying
      64             : // spans separately. If the underlying FragmentIterator has fragments
      65             : // [a,b){#2,#1} [b,c){#1} the mergingIterLevel.{next,prev} step through:
      66             : //
      67             : //      (a, start), (b, end), (b, start), (c, end)
      68             : //
      69             : // Note that (a, start) and (b, end) are observed ONCE each, despite two keys
      70             : // sharing those bounds. Also note that (b, end) and (b, start) are two distinct
      71             : // iterator positions of a mergingIterLevel.
      72             : //
      73             : // The merging iterator maintains a heap (min during forward iteration, max
      74             : // during reverse iteration) containing the boundKeys. Each boundKey is a
      75             : // 3-tuple holding the bound user key, whether the bound is a start or end key
      76             : // and the set of keys from that level that have that bound. The heap orders
      77             : // based on the boundKey's user key only.
      78             : //
      79             : // The merging iterator is responsible for merging spans across levels to
      80             : // determine which span is next, but it's also responsible for fragmenting
      81             : // overlapping spans. Consider the example:
      82             : //
      83             : //             i0:     b---d e-----h
      84             : //             i1:   a---c         h-----k
      85             : //             i2:   a------------------------------p
      86             : //
      87             : //      fragments:   a-b-c-d-e-----h-----k----------p
      88             : //
      89             : // None of the individual child iterators contain a span with the exact bounds
      90             : // [c,d), but the merging iterator must produce a span [c,d). To accomplish
      91             : // this, the merging iterator visits every span between unique boundary user
      92             : // keys. In the above example, this is:
      93             : //
      94             : //      [a,b), [b,c), [c,d), [d,e), [e, h), [h, k), [k, p)
      95             : //
      96             : // The merging iterator first initializes the heap to prepare for iteration.
      97             : // The description below discusses the mechanics of forward iteration after a
      98             : // call to First, but the mechanics are similar for reverse iteration and
      99             : // other positioning methods.
     100             : //
     101             : // During a call to First, the heap is initialized by seeking every
     102             : // mergingIterLevel to the first bound of the first fragment. In the above
     103             : // example, this seeks the child iterators to:
     104             : //
     105             : //      i0: (b, boundKindFragmentStart, [ [b,d) ])
     106             : //      i1: (a, boundKindFragmentStart, [ [a,c) ])
     107             : //      i2: (a, boundKindFragmentStart, [ [a,p) ])
     108             : //
     109             : // After fixing up the heap, the root of the heap is a boundKey with the
     110             : // smallest user key ('a' in the example). Once the heap is setup for iteration
     111             : // in the appropriate direction and location, the merging iterator uses
     112             : // find{Next,Prev}FragmentSet to find the next/previous span bounds.
     113             : //
     114             : // During forward iteration, the root of the heap's user key is the start key
     115             : // key of next merged span. findNextFragmentSet sets m.start to this user
     116             : // key. The heap may contain other boundKeys with the same user key if another
     117             : // level has a fragment starting or ending at the same key, so the
     118             : // findNextFragmentSet method pulls from the heap until it finds the first key
     119             : // greater than m.start. This key is used as the end key.
     120             : //
     121             : // In the above example, this results in m.start = 'a', m.end = 'b' and child
     122             : // iterators in the following positions:
     123             : //
     124             : //      i0: (b, boundKindFragmentStart, [ [b,d) ])
     125             : //      i1: (c, boundKindFragmentEnd,   [ [a,c) ])
     126             : //      i2: (p, boundKindFragmentEnd,   [ [a,p) ])
     127             : //
     128             : // With the user key bounds of the next merged span established,
     129             : // findNextFragmentSet must determine which, if any, fragments overlap the span.
     130             : // During forward iteration any child iterator that is now positioned at an end
     131             : // boundary has an overlapping span. (Justification: The child iterator's end
     132             : // boundary is ≥ m.end. The corresponding start boundary must be ≤ m.start since
     133             : // there were no other user keys between m.start and m.end. So the fragments
     134             : // associated with the iterator's current end boundary have start and end bounds
     135             : // such that start ≤ m.start < m.end ≤ end).
     136             : //
     137             : // findNextFragmentSet iterates over the levels, collecting keys from any child
     138             : // iterators positioned at end boundaries. In the above example, i1 and i2 are
     139             : // positioned at end boundaries, so findNextFragmentSet collects the keys of
     140             : // [a,c) and [a,p). These spans contain the merging iterator's [m.start, m.end)
     141             : // span, but they may also extend beyond the m.start and m.end. The merging
     142             : // iterator returns the keys with the merging iter's m.start and m.end bounds,
     143             : // preserving the underlying keys' sequence numbers, key kinds and values.
     144             : //
     145             : // A MergingIter is configured with a Transform that's applied to the span
     146             : // before surfacing it to the iterator user. A Transform may remove keys
     147             : // arbitrarily, but it may not modify the values themselves.
     148             : //
     149             : // It may be the case that findNextFragmentSet finds no levels positioned at end
     150             : // boundaries, or that there are no spans remaining after applying a transform,
     151             : // in which case the span [m.start, m.end) overlaps with nothing. In this case
     152             : // findNextFragmentSet loops, repeating the above process again until it finds a
     153             : // span that does contain keys.
     154             : //
     155             : // # Memory safety
     156             : //
     157             : // The FragmentIterator interface only guarantees stability of a Span and its
     158             : // associated slices until the next positioning method is called. Adjacent Spans
     159             : // may be contained in different sstables, requring the FragmentIterator
     160             : // implementation to close one sstable, releasing its memory, before opening the
     161             : // next. Most of the state used by the MergingIter is derived from spans at
     162             : // current child iterator positions only, ensuring state is stable. The one
     163             : // exception is the start bound during forward iteration and the end bound
     164             : // during reverse iteration.
     165             : //
     166             : // If the heap root originates from an end boundary when findNextFragmentSet
     167             : // begins, a Next on the heap root level may invalidate the end boundary. To
     168             : // accommodate this, find{Next,Prev}FragmentSet copy the initial boundary if the
     169             : // subsequent Next/Prev would move to the next span.
     170             : type MergingIter struct {
     171             :         comparer *base.Comparer
     172             :         *MergingBuffers
     173             :         // start and end hold the bounds for the span currently under the
     174             :         // iterator position.
     175             :         //
     176             :         // Invariant: None of the levels' iterators contain spans with a bound
     177             :         // between start and end. For all bounds b, b ≤ start || b ≥ end.
     178             :         start, end []byte
     179             : 
     180             :         // transformer defines a transformation to be applied to a span before it's
     181             :         // yielded to the user. Transforming may filter individual keys contained
     182             :         // within the span.
     183             :         transformer keyspan.Transformer
     184             :         // span holds the iterator's current span. This span is used as the
     185             :         // destination for transforms. Every tranformed span overwrites the
     186             :         // previous.
     187             :         span keyspan.Span
     188             :         dir  int8
     189             : 
     190             :         // alloc preallocates mergingIterLevel and mergingIterItems for use by the
     191             :         // merging iterator. As long as the merging iterator is used with
     192             :         // manifest.NumLevels+3 and fewer fragment iterators, the merging iterator
     193             :         // will not need to allocate upon initialization. The value NumLevels+3
     194             :         // mirrors the preallocated levels in iterAlloc used for point iterators.
     195             :         // Invariant: cap(levels) == cap(items)
     196             :         alloc struct {
     197             :                 levels [manifest.NumLevels + 3]mergingIterLevel
     198             :                 items  [manifest.NumLevels + 3]mergingIterItem
     199             :         }
     200             : }
     201             : 
     202             : // MergingBuffers holds buffers used while merging keyspans.
     203             : type MergingBuffers struct {
     204             :         // keys holds all of the keys across all levels that overlap the key span
     205             :         // [start, end), sorted by InternalKeyTrailer descending. This slice is reconstituted
     206             :         // in synthesizeKeys from each mergingIterLevel's keys every time the
     207             :         // [start, end) bounds change.
     208             :         //
     209             :         // Each element points into a child iterator's memory, so the keys may not
     210             :         // be directly modified.
     211             :         keys []keyspan.Key
     212             :         // levels holds levels allocated by MergingIter.init. The MergingIter will
     213             :         // prefer use of its `manifest.NumLevels+3` array, so this slice will be
     214             :         // longer if set.
     215             :         levels []mergingIterLevel
     216             :         wrapFn keyspan.WrapFn
     217             :         // heap holds a slice for the merging iterator heap allocated by
     218             :         // MergingIter.init. The MergingIter will prefer use of its
     219             :         // `manifest.NumLevels+3` items array, so this slice will be longer if set.
     220             :         heap mergingIterHeap
     221             :         // buf is a buffer used to save [start, end) boundary keys.
     222             :         buf []byte
     223             : }
     224             : 
     225             : // PrepareForReuse discards any excessively large buffers.
     226           1 : func (bufs *MergingBuffers) PrepareForReuse() {
     227           1 :         if cap(bufs.buf) > keyspan.BufferReuseMaxCapacity {
     228           0 :                 bufs.buf = nil
     229           0 :         }
     230             : }
     231             : 
     232             : // MergingIter implements the FragmentIterator interface.
     233             : var _ keyspan.FragmentIterator = (*MergingIter)(nil)
     234             : 
     235             : type mergingIterLevel struct {
     236             :         iter keyspan.FragmentIterator
     237             : 
     238             :         // heapKey holds the current key at this level for use within the heap.
     239             :         heapKey boundKey
     240             : }
     241             : 
     242           1 : func (l *mergingIterLevel) next() error {
     243           1 :         if l.heapKey.kind == boundKindFragmentStart {
     244           1 :                 l.heapKey = boundKey{
     245           1 :                         kind: boundKindFragmentEnd,
     246           1 :                         key:  l.heapKey.span.End,
     247           1 :                         span: l.heapKey.span,
     248           1 :                 }
     249           1 :                 return nil
     250           1 :         }
     251           1 :         s, err := l.iter.Next()
     252           1 :         switch {
     253           0 :         case err != nil:
     254           0 :                 return err
     255           1 :         case s == nil:
     256           1 :                 l.heapKey = boundKey{kind: boundKindInvalid}
     257           1 :                 return nil
     258           1 :         default:
     259           1 :                 l.heapKey = boundKey{
     260           1 :                         kind: boundKindFragmentStart,
     261           1 :                         key:  s.Start,
     262           1 :                         span: s,
     263           1 :                 }
     264           1 :                 return nil
     265             :         }
     266             : }
     267             : 
     268           1 : func (l *mergingIterLevel) prev() error {
     269           1 :         if l.heapKey.kind == boundKindFragmentEnd {
     270           1 :                 l.heapKey = boundKey{
     271           1 :                         kind: boundKindFragmentStart,
     272           1 :                         key:  l.heapKey.span.Start,
     273           1 :                         span: l.heapKey.span,
     274           1 :                 }
     275           1 :                 return nil
     276           1 :         }
     277           1 :         s, err := l.iter.Prev()
     278           1 :         switch {
     279           0 :         case err != nil:
     280           0 :                 return err
     281           1 :         case s == nil:
     282           1 :                 l.heapKey = boundKey{kind: boundKindInvalid}
     283           1 :                 return nil
     284           1 :         default:
     285           1 :                 l.heapKey = boundKey{
     286           1 :                         kind: boundKindFragmentEnd,
     287           1 :                         key:  s.End,
     288           1 :                         span: s,
     289           1 :                 }
     290           1 :                 return nil
     291             :         }
     292             : }
     293             : 
     294             : // Init initializes the merging iterator with the provided fragment iterators.
     295             : func (m *MergingIter) Init(
     296             :         comparer *base.Comparer,
     297             :         transformer keyspan.Transformer,
     298             :         bufs *MergingBuffers,
     299             :         iters ...keyspan.FragmentIterator,
     300           1 : ) {
     301           1 :         *m = MergingIter{
     302           1 :                 comparer:       comparer,
     303           1 :                 MergingBuffers: bufs,
     304           1 :                 transformer:    transformer,
     305           1 :         }
     306           1 :         m.heap.cmp = comparer.Compare
     307           1 :         levels, items := m.levels, m.heap.items
     308           1 : 
     309           1 :         // Invariant: cap(levels) >= cap(items)
     310           1 :         // Invariant: cap(alloc.levels) == cap(alloc.items)
     311           1 :         if len(iters) <= len(m.alloc.levels) {
     312           1 :                 // The slices allocated on the MergingIter struct are large enough.
     313           1 :                 m.levels = m.alloc.levels[:len(iters)]
     314           1 :                 m.heap.items = m.alloc.items[:0]
     315           1 :         } else if len(iters) <= cap(levels) {
     316           0 :                 // The existing heap-allocated slices are large enough, so reuse them.
     317           0 :                 m.levels = levels[:len(iters)]
     318           0 :                 m.heap.items = items[:0]
     319           1 :         } else {
     320           1 :                 // Heap allocate new slices.
     321           1 :                 m.levels = make([]mergingIterLevel, len(iters))
     322           1 :                 m.heap.items = make([]mergingIterItem, 0, len(iters))
     323           1 :         }
     324           1 :         for i := range m.levels {
     325           1 :                 m.levels[i] = mergingIterLevel{iter: iters[i]}
     326           1 :                 if m.wrapFn != nil {
     327           0 :                         m.levels[i].iter = m.wrapFn(m.levels[i].iter)
     328           0 :                 }
     329             :         }
     330             : }
     331             : 
     332             : // AddLevel adds a new level to the bottom of the merging iterator. AddLevel
     333             : // must be called after Init and before any other method.
     334           1 : func (m *MergingIter) AddLevel(iter keyspan.FragmentIterator) {
     335           1 :         if m.wrapFn != nil {
     336           0 :                 iter = m.wrapFn(iter)
     337           0 :         }
     338           1 :         m.levels = append(m.levels, mergingIterLevel{iter: iter})
     339             : }
     340             : 
     341             : // SeekGE moves the iterator to the first span covering a key greater than
     342             : // or equal to the given key. This is equivalent to seeking to the first
     343             : // span with an end key greater than the given key.
     344           1 : func (m *MergingIter) SeekGE(key []byte) (*keyspan.Span, error) {
     345           1 :         // SeekGE(k) seeks to the first span with an end key greater than the given
     346           1 :         // key. The merged span M that we're searching for might straddle the seek
     347           1 :         // `key`. In this case, the M.Start may be a key ≤ the seek key.
     348           1 :         //
     349           1 :         // Consider a SeekGE(dog) in the following example.
     350           1 :         //
     351           1 :         //            i0:     b---d e-----h
     352           1 :         //            i1:   a---c         h-----k
     353           1 :         //            i2:   a------------------------------p
     354           1 :         //        merged:   a-b-c-d-e-----h-----k----------p
     355           1 :         //
     356           1 :         // The merged span M containing 'dog' is [d,e). The 'd' of the merged span
     357           1 :         // comes from i0's [b,d)'s end boundary. The [b,d) span does not cover any
     358           1 :         // key >= dog, so we cannot find the span by positioning the child iterators
     359           1 :         // using a SeekGE(dog).
     360           1 :         //
     361           1 :         // Instead, if we take all the child iterators' spans bounds:
     362           1 :         //                  a b c d e     h     k          p
     363           1 :         // We want to partition them into keys ≤ `key` and keys > `key`.
     364           1 :         //                        dog
     365           1 :         //                         │
     366           1 :         //                  a b c d│e     h     k          p
     367           1 :         //                         │
     368           1 :         // The largest key on the left of the partition forms the merged span's
     369           1 :         // start key, and the smallest key on the right of the partition forms the
     370           1 :         // merged span's end key. Recharacterized:
     371           1 :         //
     372           1 :         //   M.Start: the largest boundary ≤ k of any child span
     373           1 :         //   M.End:   the smallest boundary > k of any child span
     374           1 :         //
     375           1 :         // The FragmentIterator interface doesn't implement seeking by all bounds,
     376           1 :         // it implements seeking by containment. A SeekGE(k) will ensure we observe
     377           1 :         // all start boundaries ≥ k and all end boundaries > k but does not ensure
     378           1 :         // we observe end boundaries = k or any boundaries < k.  A SeekLT(k) will
     379           1 :         // ensure we observe all start boundaries < k and all end boundaries ≤ k but
     380           1 :         // does not ensure we observe any start boundaries = k or any boundaries >
     381           1 :         // k. This forces us to seek in one direction and step in the other.
     382           1 :         //
     383           1 :         // In a SeekGE, we want to end up oriented in the forward direction when
     384           1 :         // complete, so we begin with searching for M.Start by SeekLT-ing every
     385           1 :         // child iterator to `k`.  For every child span found, we determine the
     386           1 :         // largest bound ≤ `k` and use it to initialize our max heap. The resulting
     387           1 :         // root of the max heap is a preliminary value for `M.Start`.
     388           1 :         for i := range m.levels {
     389           1 :                 l := &m.levels[i]
     390           1 :                 s, err := l.iter.SeekLT(key)
     391           1 :                 switch {
     392           0 :                 case err != nil:
     393           0 :                         return nil, err
     394           1 :                 case s == nil:
     395           1 :                         l.heapKey = boundKey{kind: boundKindInvalid}
     396           1 :                 case m.comparer.Compare(s.End, key) <= 0:
     397           1 :                         l.heapKey = boundKey{
     398           1 :                                 kind: boundKindFragmentEnd,
     399           1 :                                 key:  s.End,
     400           1 :                                 span: s,
     401           1 :                         }
     402           1 :                 default:
     403           1 :                         // s.End > key && s.Start < key
     404           1 :                         // We need to use this span's start bound, since that's the largest
     405           1 :                         // bound ≤ key.
     406           1 :                         l.heapKey = boundKey{
     407           1 :                                 kind: boundKindFragmentStart,
     408           1 :                                 key:  s.Start,
     409           1 :                                 span: s,
     410           1 :                         }
     411             :                 }
     412             :         }
     413           1 :         m.initMaxHeap()
     414           1 :         if len(m.heap.items) == 0 {
     415           1 :                 // There are no spans covering any key < `key`. There is no span that
     416           1 :                 // straddles the seek key. Reorient the heap into a min heap and return
     417           1 :                 // the first span we find in the forward direction.
     418           1 :                 if err := m.switchToMinHeap(); err != nil {
     419           0 :                         return nil, err
     420           0 :                 }
     421           1 :                 return m.findNextFragmentSet()
     422             :         }
     423             : 
     424             :         // The heap root is now the largest boundary key b such that:
     425             :         //   1. b < k
     426             :         //   2. b = k, and b is an end boundary
     427             :         // There's a third case that we will need to consider later, after we've
     428             :         // switched to a min heap:
     429             :         //   3. there exists a start boundary key b such that b = k.
     430             :         // A start boundary key equal to k would not be surfaced when we seeked all
     431             :         // the levels using SeekLT(k), since no key <k would be covered within a
     432             :         // span within an inclusive `k` start boundary.
     433             :         //
     434             :         // Assume that the tightest boundary ≤ k is the current heap root (cases 1 &
     435             :         // 2). After we switch to a min heap, we'll check for the third case and
     436             :         // adjust the start boundary if necessary.
     437           1 :         m.start = m.heap.items[0].boundKey.key
     438           1 : 
     439           1 :         // Before switching the direction of the heap, save a copy of the start
     440           1 :         // boundary if it's the end boundary of some child span. Next-ing the child
     441           1 :         // iterator might switch files and invalidate the memory of the bound.
     442           1 :         if m.heap.items[0].boundKey.kind == boundKindFragmentEnd {
     443           1 :                 m.buf = append(m.buf[:0], m.start...)
     444           1 :                 m.start = m.buf
     445           1 :         }
     446             : 
     447             :         // Switch to a min heap. This will move each level to the next bound in
     448             :         // every level, and then establish a min heap. This allows us to obtain the
     449             :         // smallest boundary key > `key`, which will serve as our candidate end
     450             :         // bound.
     451           1 :         if err := m.switchToMinHeap(); err != nil {
     452           0 :                 return nil, err
     453           1 :         } else if len(m.heap.items) == 0 {
     454           1 :                 return nil, nil
     455           1 :         }
     456             : 
     457             :         // Check for the case 3 described above. It's possible that when we switch
     458             :         // heap directions, we discover a start boundary of some child span that is
     459             :         // equal to the seek key `key`. In this case, we want this key to be our
     460             :         // start boundary.
     461           1 :         if m.heap.items[0].boundKey.kind == boundKindFragmentStart &&
     462           1 :                 m.comparer.Equal(m.heap.items[0].boundKey.key, key) {
     463           1 :                 // Call findNextFragmentSet, which will set m.start to the heap root and
     464           1 :                 // proceed forward.
     465           1 :                 return m.findNextFragmentSet()
     466           1 :         }
     467             : 
     468           1 :         m.end = m.heap.items[0].boundKey.key
     469           1 :         if found, s, err := m.synthesizeKeys(+1); err != nil {
     470           0 :                 return nil, err
     471           1 :         } else if found && s != nil {
     472           1 :                 return s, nil
     473           1 :         }
     474           1 :         return m.findNextFragmentSet()
     475             : }
     476             : 
     477             : // SeekLT moves the iterator to the last span covering a key less than the
     478             : // given key. This is equivalent to seeking to the last span with a start
     479             : // key less than the given key.
     480           1 : func (m *MergingIter) SeekLT(key []byte) (*keyspan.Span, error) {
     481           1 :         // SeekLT(k) seeks to the last span with a start key less than the given
     482           1 :         // key. The merged span M that we're searching for might straddle the seek
     483           1 :         // `key`. In this case, the M.End may be a key ≥ the seek key.
     484           1 :         //
     485           1 :         // Consider a SeekLT(dog) in the following example.
     486           1 :         //
     487           1 :         //            i0:     b---d e-----h
     488           1 :         //            i1:   a---c         h-----k
     489           1 :         //            i2:   a------------------------------p
     490           1 :         //        merged:   a-b-c-d-e-----h-----k----------p
     491           1 :         //
     492           1 :         // The merged span M containing the largest key <'dog' is [d,e). The 'e' of
     493           1 :         // the merged span comes from i0's [e,h)'s start boundary. The [e,h) span
     494           1 :         // does not cover any key < dog, so we cannot find the span by positioning
     495           1 :         // the child iterators using a SeekLT(dog).
     496           1 :         //
     497           1 :         // Instead, if we take all the child iterators' spans bounds:
     498           1 :         //                  a b c d e     h     k          p
     499           1 :         // We want to partition them into keys < `key` and keys ≥ `key`.
     500           1 :         //                        dog
     501           1 :         //                         │
     502           1 :         //                  a b c d│e     h     k          p
     503           1 :         //                         │
     504           1 :         // The largest key on the left of the partition forms the merged span's
     505           1 :         // start key, and the smallest key on the right of the partition forms the
     506           1 :         // merged span's end key. Recharacterized:
     507           1 :         //
     508           1 :         //   M.Start: the largest boundary < k of any child span
     509           1 :         //   M.End:   the smallest boundary ≥ k of any child span
     510           1 :         //
     511           1 :         // The FragmentIterator interface doesn't implement seeking by all bounds,
     512           1 :         // it implements seeking by containment. A SeekGE(k) will ensure we observe
     513           1 :         // all start boundaries ≥ k and all end boundaries > k but does not ensure
     514           1 :         // we observe end boundaries = k or any boundaries < k.  A SeekLT(k) will
     515           1 :         // ensure we observe all start boundaries < k and all end boundaries ≤ k but
     516           1 :         // does not ensure we observe any start boundaries = k or any boundaries >
     517           1 :         // k. This forces us to seek in one direction and step in the other.
     518           1 :         //
     519           1 :         // In a SeekLT, we want to end up oriented in the backward direction when
     520           1 :         // complete, so we begin with searching for M.End by SeekGE-ing every
     521           1 :         // child iterator to `k`. For every child span found, we determine the
     522           1 :         // smallest bound ≥ `k` and use it to initialize our min heap. The resulting
     523           1 :         // root of the min heap is a preliminary value for `M.End`.
     524           1 :         for i := range m.levels {
     525           1 :                 l := &m.levels[i]
     526           1 :                 s, err := l.iter.SeekGE(key)
     527           1 :                 switch {
     528           0 :                 case err != nil:
     529           0 :                         return nil, err
     530           1 :                 case s == nil:
     531           1 :                         l.heapKey = boundKey{kind: boundKindInvalid}
     532           1 :                 case m.comparer.Compare(s.Start, key) >= 0:
     533           1 :                         l.heapKey = boundKey{
     534           1 :                                 kind: boundKindFragmentStart,
     535           1 :                                 key:  s.Start,
     536           1 :                                 span: s,
     537           1 :                         }
     538           1 :                 default:
     539           1 :                         // s.Start < key
     540           1 :                         // We need to use this span's end bound, since that's the smallest
     541           1 :                         // bound > key.
     542           1 :                         l.heapKey = boundKey{
     543           1 :                                 kind: boundKindFragmentEnd,
     544           1 :                                 key:  s.End,
     545           1 :                                 span: s,
     546           1 :                         }
     547             :                 }
     548             :         }
     549           1 :         m.initMinHeap()
     550           1 :         if len(m.heap.items) == 0 {
     551           1 :                 // There are no spans covering any key ≥ `key`. There is no span that
     552           1 :                 // straddles the seek key. Reorient the heap into a max heap and return
     553           1 :                 // the first span we find in the reverse direction.
     554           1 :                 if err := m.switchToMaxHeap(); err != nil {
     555           0 :                         return nil, err
     556           0 :                 }
     557           1 :                 return m.findPrevFragmentSet()
     558             :         }
     559             : 
     560             :         // The heap root is now the smallest boundary key b such that:
     561             :         //   1. b > k
     562             :         //   2. b = k, and b is a start boundary
     563             :         // There's a third case that we will need to consider later, after we've
     564             :         // switched to a max heap:
     565             :         //   3. there exists an end boundary key b such that b = k.
     566             :         // An end boundary key equal to k would not be surfaced when we seeked all
     567             :         // the levels using SeekGE(k), since k would not be contained within the
     568             :         // exclusive end boundary.
     569             :         //
     570             :         // Assume that the tightest boundary ≥ k is the current heap root (cases 1 &
     571             :         // 2). After we switch to a max heap, we'll check for the third case and
     572             :         // adjust the end boundary if necessary.
     573           1 :         m.end = m.heap.items[0].boundKey.key
     574           1 : 
     575           1 :         // Before switching the direction of the heap, save a copy of the end
     576           1 :         // boundary if it's the start boundary of some child span. Prev-ing the
     577           1 :         // child iterator might switch files and invalidate the memory of the bound.
     578           1 :         if m.heap.items[0].boundKey.kind == boundKindFragmentStart {
     579           1 :                 m.buf = append(m.buf[:0], m.end...)
     580           1 :                 m.end = m.buf
     581           1 :         }
     582             : 
     583             :         // Switch to a max heap. This will move each level to the previous bound in
     584             :         // every level, and then establish a max heap. This allows us to obtain the
     585             :         // largest boundary key < `key`, which will serve as our candidate start
     586             :         // bound.
     587           1 :         if err := m.switchToMaxHeap(); err != nil {
     588           0 :                 return nil, err
     589           1 :         } else if len(m.heap.items) == 0 {
     590           1 :                 return nil, nil
     591           1 :         }
     592             :         // Check for the case 3 described above. It's possible that when we switch
     593             :         // heap directions, we discover an end boundary of some child span that is
     594             :         // equal to the seek key `key`. In this case, we want this key to be our end
     595             :         // boundary.
     596           1 :         if m.heap.items[0].boundKey.kind == boundKindFragmentEnd &&
     597           1 :                 m.comparer.Equal(m.heap.items[0].boundKey.key, key) {
     598           1 :                 // Call findPrevFragmentSet, which will set m.end to the heap root and
     599           1 :                 // proceed backwards.
     600           1 :                 return m.findPrevFragmentSet()
     601           1 :         }
     602             : 
     603           1 :         m.start = m.heap.items[0].boundKey.key
     604           1 :         if found, s, err := m.synthesizeKeys(-1); err != nil {
     605           0 :                 return nil, err
     606           1 :         } else if found && s != nil {
     607           1 :                 return s, nil
     608           1 :         }
     609           1 :         return m.findPrevFragmentSet()
     610             : }
     611             : 
     612             : // First seeks the iterator to the first span.
     613           1 : func (m *MergingIter) First() (*keyspan.Span, error) {
     614           1 :         for i := range m.levels {
     615           1 :                 s, err := m.levels[i].iter.First()
     616           1 :                 switch {
     617           0 :                 case err != nil:
     618           0 :                         return nil, err
     619           1 :                 case s == nil:
     620           1 :                         m.levels[i].heapKey = boundKey{kind: boundKindInvalid}
     621           1 :                 default:
     622           1 :                         m.levels[i].heapKey = boundKey{
     623           1 :                                 kind: boundKindFragmentStart,
     624           1 :                                 key:  s.Start,
     625           1 :                                 span: s,
     626           1 :                         }
     627             :                 }
     628             :         }
     629           1 :         m.initMinHeap()
     630           1 :         return m.findNextFragmentSet()
     631             : }
     632             : 
     633             : // Last seeks the iterator to the last span.
     634           1 : func (m *MergingIter) Last() (*keyspan.Span, error) {
     635           1 :         for i := range m.levels {
     636           1 :                 s, err := m.levels[i].iter.Last()
     637           1 :                 switch {
     638           0 :                 case err != nil:
     639           0 :                         return nil, err
     640           0 :                 case s == nil:
     641           0 :                         m.levels[i].heapKey = boundKey{kind: boundKindInvalid}
     642           1 :                 default:
     643           1 :                         m.levels[i].heapKey = boundKey{
     644           1 :                                 kind: boundKindFragmentEnd,
     645           1 :                                 key:  s.End,
     646           1 :                                 span: s,
     647           1 :                         }
     648             :                 }
     649             :         }
     650           1 :         m.initMaxHeap()
     651           1 :         return m.findPrevFragmentSet()
     652             : }
     653             : 
     654             : // Next advances the iterator to the next span.
     655           1 : func (m *MergingIter) Next() (*keyspan.Span, error) {
     656           1 :         if m.dir == +1 && (m.end == nil || m.start == nil) {
     657           0 :                 return nil, nil
     658           0 :         }
     659           1 :         if m.dir != +1 {
     660           1 :                 if err := m.switchToMinHeap(); err != nil {
     661           0 :                         return nil, err
     662           0 :                 }
     663             :         }
     664           1 :         return m.findNextFragmentSet()
     665             : }
     666             : 
     667             : // Prev advances the iterator to the previous span.
     668           1 : func (m *MergingIter) Prev() (*keyspan.Span, error) {
     669           1 :         if m.dir == -1 && (m.end == nil || m.start == nil) {
     670           0 :                 return nil, nil
     671           0 :         }
     672           1 :         if m.dir != -1 {
     673           1 :                 if err := m.switchToMaxHeap(); err != nil {
     674           0 :                         return nil, err
     675           0 :                 }
     676             :         }
     677           1 :         return m.findPrevFragmentSet()
     678             : }
     679             : 
     680             : // SetContext is part of the FragmentIterator interface.
     681           0 : func (m *MergingIter) SetContext(ctx context.Context) {
     682           0 :         for i := range m.levels {
     683           0 :                 m.levels[i].iter.SetContext(ctx)
     684           0 :         }
     685             : }
     686             : 
     687             : // Close closes the iterator, releasing all acquired resources.
     688           1 : func (m *MergingIter) Close() {
     689           1 :         for i := range m.levels {
     690           1 :                 m.levels[i].iter.Close()
     691           1 :         }
     692           1 :         m.levels = nil
     693           1 :         m.heap.items = m.heap.items[:0]
     694             : }
     695             : 
     696             : // String implements fmt.Stringer.
     697           0 : func (m *MergingIter) String() string {
     698           0 :         return "merging-keyspan"
     699           0 : }
     700             : 
     701           1 : func (m *MergingIter) initMinHeap() {
     702           1 :         m.dir = +1
     703           1 :         m.heap.reverse = false
     704           1 :         m.initHeap()
     705           1 : }
     706             : 
     707           1 : func (m *MergingIter) initMaxHeap() {
     708           1 :         m.dir = -1
     709           1 :         m.heap.reverse = true
     710           1 :         m.initHeap()
     711           1 : }
     712             : 
     713           1 : func (m *MergingIter) initHeap() {
     714           1 :         m.heap.items = m.heap.items[:0]
     715           1 :         for i := range m.levels {
     716           1 :                 if l := &m.levels[i]; l.heapKey.kind != boundKindInvalid {
     717           1 :                         m.heap.items = append(m.heap.items, mergingIterItem{
     718           1 :                                 index:    i,
     719           1 :                                 boundKey: &l.heapKey,
     720           1 :                         })
     721           1 :                 }
     722             :         }
     723           1 :         m.heap.init()
     724             : }
     725             : 
     726           1 : func (m *MergingIter) switchToMinHeap() error {
     727           1 :         // switchToMinHeap reorients the heap for forward iteration, without moving
     728           1 :         // the current MergingIter position.
     729           1 : 
     730           1 :         // The iterator is currently positioned at the span [m.start, m.end),
     731           1 :         // oriented in the reverse direction, so each level's iterator is positioned
     732           1 :         // to the largest key ≤ m.start. To reorient in the forward direction, we
     733           1 :         // must advance each level's iterator to the smallest key ≥ m.end. Consider
     734           1 :         // this three-level example.
     735           1 :         //
     736           1 :         //         i0:     b---d e-----h
     737           1 :         //         i1:   a---c         h-----k
     738           1 :         //         i2:   a------------------------------p
     739           1 :         //
     740           1 :         //     merged:   a-b-c-d-e-----h-----k----------p
     741           1 :         //
     742           1 :         // If currently positioned at the merged span [c,d), then the level
     743           1 :         // iterators' heap keys are:
     744           1 :         //
     745           1 :         //    i0: (b, [b, d))   i1: (c, [a,c))   i2: (a, [a,p))
     746           1 :         //
     747           1 :         // Reversing the heap should not move the merging iterator and should not
     748           1 :         // change the current [m.start, m.end) bounds. It should only prepare for
     749           1 :         // forward iteration by updating the child iterators' heap keys to:
     750           1 :         //
     751           1 :         //    i0: (d, [b, d))   i1: (h, [h,k))   i2: (p, [a,p))
     752           1 :         //
     753           1 :         // In every level the first key ≥ m.end is the next in the iterator.
     754           1 :         // Justification: Suppose not and a level iterator's next key was some key k
     755           1 :         // such that k < m.end. The max-heap invariant dictates that the current
     756           1 :         // iterator position is the largest entry with a user key ≥ m.start. This
     757           1 :         // means k > m.start. We started with the assumption that k < m.end, so
     758           1 :         // m.start < k < m.end. But then k is between our current span bounds,
     759           1 :         // and reverse iteration would have constructed the current interval to be
     760           1 :         // [k, m.end) not [m.start, m.end).
     761           1 : 
     762           1 :         if invariants.Enabled {
     763           1 :                 for i := range m.levels {
     764           1 :                         l := &m.levels[i]
     765           1 :                         if l.heapKey.kind != boundKindInvalid && m.comparer.Compare(l.heapKey.key, m.start) > 0 {
     766           0 :                                 panic("pebble: invariant violation: max-heap key > m.start")
     767             :                         }
     768             :                 }
     769             :         }
     770             : 
     771           1 :         for i := range m.levels {
     772           1 :                 if err := m.levels[i].next(); err != nil {
     773           0 :                         return err
     774           0 :                 }
     775             :         }
     776           1 :         m.initMinHeap()
     777           1 :         return nil
     778             : }
     779             : 
     780           1 : func (m *MergingIter) switchToMaxHeap() error {
     781           1 :         // switchToMaxHeap reorients the heap for reverse iteration, without moving
     782           1 :         // the current MergingIter position.
     783           1 : 
     784           1 :         // The iterator is currently positioned at the span [m.start, m.end),
     785           1 :         // oriented in the forward direction. Each level's iterator is positioned at
     786           1 :         // the smallest bound ≥ m.end. To reorient in the reverse direction, we must
     787           1 :         // move each level's iterator to the largest key ≤ m.start. Consider this
     788           1 :         // three-level example.
     789           1 :         //
     790           1 :         //         i0:     b---d e-----h
     791           1 :         //         i1:   a---c         h-----k
     792           1 :         //         i2:   a------------------------------p
     793           1 :         //
     794           1 :         //     merged:   a-b-c-d-e-----h-----k----------p
     795           1 :         //
     796           1 :         // If currently positioned at the merged span [c,d), then the level
     797           1 :         // iterators' heap keys are:
     798           1 :         //
     799           1 :         //    i0: (d, [b, d))   i1: (h, [h,k))   i2: (p, [a,p))
     800           1 :         //
     801           1 :         // Reversing the heap should not move the merging iterator and should not
     802           1 :         // change the current [m.start, m.end) bounds. It should only prepare for
     803           1 :         // reverse iteration by updating the child iterators' heap keys to:
     804           1 :         //
     805           1 :         //    i0: (b, [b, d))   i1: (c, [a,c))   i2: (a, [a,p))
     806           1 :         //
     807           1 :         // In every level the largest key ≤ m.start is the prev in the iterator.
     808           1 :         // Justification: Suppose not and a level iterator's prev key was some key k
     809           1 :         // such that k > m.start. The min-heap invariant dictates that the current
     810           1 :         // iterator position is the smallest entry with a user key ≥ m.end. This
     811           1 :         // means k < m.end, otherwise the iterator would be positioned at k. We
     812           1 :         // started with the assumption that k > m.start, so m.start < k < m.end. But
     813           1 :         // then k is between our current span bounds, and reverse iteration
     814           1 :         // would have constructed the current interval to be [m.start, k) not
     815           1 :         // [m.start, m.end).
     816           1 : 
     817           1 :         if invariants.Enabled {
     818           1 :                 for i := range m.levels {
     819           1 :                         l := &m.levels[i]
     820           1 :                         if l.heapKey.kind != boundKindInvalid && m.comparer.Compare(l.heapKey.key, m.end) < 0 {
     821           0 :                                 panic("pebble: invariant violation: min-heap key < m.end")
     822             :                         }
     823             :                 }
     824             :         }
     825             : 
     826           1 :         for i := range m.levels {
     827           1 :                 if err := m.levels[i].prev(); err != nil {
     828           0 :                         return err
     829           0 :                 }
     830             :         }
     831           1 :         m.initMaxHeap()
     832           1 :         return nil
     833             : }
     834             : 
     835           1 : func (m *MergingIter) findNextFragmentSet() (*keyspan.Span, error) {
     836           1 :         // Each iteration of this loop considers a new merged span between unique
     837           1 :         // user keys. An iteration may find that there exists no overlap for a given
     838           1 :         // span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
     839           1 :         // below loop will still consider [b,d) before continuing to [d, e)). It
     840           1 :         // returns when it finds a span that is covered by at least one key.
     841           1 : 
     842           1 :         for m.heap.len() > 0 {
     843           1 :                 // Initialize the next span's start bound. SeekGE and First prepare the
     844           1 :                 // heap without advancing. Next leaves the heap in a state such that the
     845           1 :                 // root is the smallest bound key equal to the returned span's end key,
     846           1 :                 // so the heap is already positioned at the next merged span's start key.
     847           1 : 
     848           1 :                 // NB: m.heapRoot() might be either an end boundary OR a start boundary
     849           1 :                 // of a level's span. Both end and start boundaries may still be a start
     850           1 :                 // key of a span in the set of fragmented spans returned by MergingIter.
     851           1 :                 // Consider the scenario:
     852           1 :                 //       a----------l      #1
     853           1 :                 //         b-----------m   #2
     854           1 :                 //
     855           1 :                 // The merged, fully-fragmented spans that MergingIter exposes to the caller
     856           1 :                 // have bounds:
     857           1 :                 //        a-b              #1
     858           1 :                 //          b--------l     #1
     859           1 :                 //          b--------l     #2
     860           1 :                 //                   l-m   #2
     861           1 :                 //
     862           1 :                 // When advancing to l-m#2, we must set m.start to 'l', which originated
     863           1 :                 // from [a,l)#1's end boundary.
     864           1 :                 m.start = m.heap.items[0].boundKey.key
     865           1 : 
     866           1 :                 // Before calling nextEntry, consider whether it might invalidate our
     867           1 :                 // start boundary. If the start boundary key originated from an end
     868           1 :                 // boundary, then we need to copy the start key before advancing the
     869           1 :                 // underlying iterator to the next Span.
     870           1 :                 if m.heap.items[0].boundKey.kind == boundKindFragmentEnd {
     871           1 :                         m.buf = append(m.buf[:0], m.start...)
     872           1 :                         m.start = m.buf
     873           1 :                 }
     874             : 
     875             :                 // There may be many entries all with the same user key. Spans in other
     876             :                 // levels may also start or end at this same user key. For eg:
     877             :                 // L1:   [a, c) [c, d)
     878             :                 // L2:          [c, e)
     879             :                 // If we're positioned at L1's end(c) end boundary, we want to advance
     880             :                 // to the first bound > c.
     881           1 :                 if err := m.nextEntry(); err != nil {
     882           0 :                         return nil, err
     883           0 :                 }
     884           1 :                 for len(m.heap.items) > 0 && m.comparer.Equal(m.heapRoot(), m.start) {
     885           1 :                         if err := m.nextEntry(); err != nil {
     886           0 :                                 return nil, err
     887           0 :                         }
     888             :                 }
     889           1 :                 if len(m.heap.items) == 0 {
     890           1 :                         break
     891             :                 }
     892             : 
     893             :                 // The current entry at the top of the heap is the first key > m.start.
     894             :                 // It must become the end bound for the span we will return to the user.
     895             :                 // In the above example, the root of the heap is L1's end(d).
     896           1 :                 m.end = m.heap.items[0].boundKey.key
     897           1 : 
     898           1 :                 // Each level within m.levels may have a span that overlaps the
     899           1 :                 // fragmented key span [m.start, m.end). Update m.keys to point to them
     900           1 :                 // and sort them by kind, sequence number. There may not be any keys
     901           1 :                 // defined over [m.start, m.end) if we're between the end of one span
     902           1 :                 // and the start of the next, OR if the configured transform filters any
     903           1 :                 // keys out. We allow empty spans that were emitted by child iterators, but
     904           1 :                 // we elide empty spans created by the mergingIter itself that don't overlap
     905           1 :                 // with any child iterator returned spans (i.e. empty spans that bridge two
     906           1 :                 // distinct child-iterator-defined spans).
     907           1 :                 if found, s, err := m.synthesizeKeys(+1); err != nil {
     908           0 :                         return nil, err
     909           1 :                 } else if found && s != nil {
     910           1 :                         return s, nil
     911           1 :                 }
     912             :         }
     913             :         // Exhausted.
     914           1 :         m.clear()
     915           1 :         return nil, nil
     916             : }
     917             : 
     918           1 : func (m *MergingIter) findPrevFragmentSet() (*keyspan.Span, error) {
     919           1 :         // Each iteration of this loop considers a new merged span between unique
     920           1 :         // user keys. An iteration may find that there exists no overlap for a given
     921           1 :         // span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
     922           1 :         // below loop will still consider [b,d) before continuing to [a, b)). It
     923           1 :         // returns when it finds a span that is covered by at least one key.
     924           1 : 
     925           1 :         for m.heap.len() > 0 {
     926           1 :                 // Initialize the next span's end bound. SeekLT and Last prepare the
     927           1 :                 // heap without advancing. Prev leaves the heap in a state such that the
     928           1 :                 // root is the largest bound key equal to the returned span's start key,
     929           1 :                 // so the heap is already positioned at the next merged span's end key.
     930           1 : 
     931           1 :                 // NB: m.heapRoot() might be either an end boundary OR a start boundary
     932           1 :                 // of a level's span. Both end and start boundaries may still be a start
     933           1 :                 // key of a span returned by MergingIter. Consider the scenario:
     934           1 :                 //       a----------l      #2
     935           1 :                 //         b-----------m   #1
     936           1 :                 //
     937           1 :                 // The merged, fully-fragmented spans that MergingIter exposes to the caller
     938           1 :                 // have bounds:
     939           1 :                 //        a-b              #2
     940           1 :                 //          b--------l     #2
     941           1 :                 //          b--------l     #1
     942           1 :                 //                   l-m   #1
     943           1 :                 //
     944           1 :                 // When Preving to a-b#2, we must set m.end to 'b', which originated
     945           1 :                 // from [b,m)#1's start boundary.
     946           1 :                 m.end = m.heap.items[0].boundKey.key
     947           1 : 
     948           1 :                 // Before calling prevEntry, consider whether it might invalidate our
     949           1 :                 // end boundary. If the end boundary key originated from a start
     950           1 :                 // boundary, then we need to copy the end key before advancing the
     951           1 :                 // underlying iterator to the previous Span.
     952           1 :                 if m.heap.items[0].boundKey.kind == boundKindFragmentStart {
     953           1 :                         m.buf = append(m.buf[:0], m.end...)
     954           1 :                         m.end = m.buf
     955           1 :                 }
     956             : 
     957             :                 // There may be many entries all with the same user key. Spans in other
     958             :                 // levels may also start or end at this same user key. For eg:
     959             :                 // L1:   [a, c) [c, d)
     960             :                 // L2:          [c, e)
     961             :                 // If we're positioned at L1's start(c) start boundary, we want to prev
     962             :                 // to move to the first bound < c.
     963           1 :                 if err := m.prevEntry(); err != nil {
     964           0 :                         return nil, err
     965           0 :                 }
     966           1 :                 for len(m.heap.items) > 0 && m.comparer.Equal(m.heapRoot(), m.end) {
     967           1 :                         if err := m.prevEntry(); err != nil {
     968           0 :                                 return nil, err
     969           0 :                         }
     970             :                 }
     971           1 :                 if len(m.heap.items) == 0 {
     972           1 :                         break
     973             :                 }
     974             : 
     975             :                 // The current entry at the top of the heap is the first key < m.end.
     976             :                 // It must become the start bound for the span we will return to the
     977             :                 // user. In the above example, the root of the heap is L1's start(a).
     978           1 :                 m.start = m.heap.items[0].boundKey.key
     979           1 : 
     980           1 :                 // Each level within m.levels may have a set of keys that overlap the
     981           1 :                 // fragmented key span [m.start, m.end). Update m.keys to point to them
     982           1 :                 // and sort them by kind, sequence number. There may not be any keys
     983           1 :                 // spanning [m.start, m.end) if we're between the end of one span and
     984           1 :                 // the start of the next, OR if the configured transform filters any
     985           1 :                 // keys out.  We allow empty spans that were emitted by child iterators, but
     986           1 :                 // we elide empty spans created by the mergingIter itself that don't overlap
     987           1 :                 // with any child iterator returned spans (i.e. empty spans that bridge two
     988           1 :                 // distinct child-iterator-defined spans).
     989           1 :                 if found, s, err := m.synthesizeKeys(-1); err != nil {
     990           0 :                         return nil, err
     991           1 :                 } else if found && s != nil {
     992           1 :                         return s, nil
     993           1 :                 }
     994             :         }
     995             :         // Exhausted.
     996           1 :         m.clear()
     997           1 :         return nil, nil
     998             : }
     999             : 
    1000           1 : func (m *MergingIter) heapRoot() []byte {
    1001           1 :         return m.heap.items[0].boundKey.key
    1002           1 : }
    1003             : 
    1004             : // synthesizeKeys is called by find{Next,Prev}FragmentSet to populate and
    1005             : // sort the set of keys overlapping [m.start, m.end).
    1006             : //
    1007             : // During forward iteration, if the current heap item is a fragment end,
    1008             : // then the fragment's start must be ≤ m.start and the fragment overlaps the
    1009             : // current iterator position of [m.start, m.end).
    1010             : //
    1011             : // During reverse iteration, if the current heap item is a fragment start,
    1012             : // then the fragment's end must be ≥ m.end and the fragment overlaps the
    1013             : // current iteration position of [m.start, m.end).
    1014             : //
    1015             : // The boolean return value, `found`, is true if the returned span overlaps
    1016             : // with a span returned by a child iterator.
    1017           1 : func (m *MergingIter) synthesizeKeys(dir int8) (bool, *keyspan.Span, error) {
    1018           1 :         if invariants.Enabled {
    1019           1 :                 if m.comparer.Compare(m.start, m.end) >= 0 {
    1020           0 :                         panic(fmt.Sprintf("pebble: invariant violation: span start ≥ end: %s >= %s", m.start, m.end))
    1021             :                 }
    1022             :         }
    1023             : 
    1024           1 :         m.keys = m.keys[:0]
    1025           1 :         found := false
    1026           1 :         for i := range m.levels {
    1027           1 :                 if dir == +1 && m.levels[i].heapKey.kind == boundKindFragmentEnd ||
    1028           1 :                         dir == -1 && m.levels[i].heapKey.kind == boundKindFragmentStart {
    1029           1 :                         m.keys = append(m.keys, m.levels[i].heapKey.span.Keys...)
    1030           1 :                         found = true
    1031           1 :                 }
    1032             :         }
    1033             :         // Sort the keys by sequence number in descending order.
    1034             :         //
    1035             :         // TODO(jackson): We should be able to remove this sort and instead
    1036             :         // guarantee that we'll return keys in the order of the levels they're from.
    1037             :         // With careful iterator construction, this would  guarantee that they're
    1038             :         // sorted by trailer descending for the range key iteration use case.
    1039           1 :         slices.SortFunc(m.keys, func(a, b keyspan.Key) int {
    1040           1 :                 return cmp.Compare(b.Trailer, a.Trailer)
    1041           1 :         })
    1042             : 
    1043             :         // Apply the configured transform. See VisibleTransform.
    1044           1 :         m.span = keyspan.Span{
    1045           1 :                 Start:     m.start,
    1046           1 :                 End:       m.end,
    1047           1 :                 Keys:      m.keys,
    1048           1 :                 KeysOrder: keyspan.ByTrailerDesc,
    1049           1 :         }
    1050           1 :         if err := m.transformer.Transform(m.comparer.CompareSuffixes, m.span, &m.span); err != nil {
    1051           0 :                 return false, nil, err
    1052           0 :         }
    1053           1 :         return found, &m.span, nil
    1054             : }
    1055             : 
    1056           1 : func (m *MergingIter) clear() {
    1057           1 :         for fi := range m.keys {
    1058           1 :                 m.keys[fi] = keyspan.Key{}
    1059           1 :         }
    1060           1 :         m.keys = m.keys[:0]
    1061             : }
    1062             : 
    1063             : // nextEntry steps to the next entry.
    1064           1 : func (m *MergingIter) nextEntry() error {
    1065           1 :         l := &m.levels[m.heap.items[0].index]
    1066           1 :         if err := l.next(); err != nil {
    1067           0 :                 return err
    1068           0 :         }
    1069           1 :         if !l.heapKey.valid() {
    1070           1 :                 // l.iter is exhausted.
    1071           1 :                 m.heap.pop()
    1072           1 :                 return nil
    1073           1 :         }
    1074             : 
    1075           1 :         if m.heap.len() > 1 {
    1076           1 :                 m.heap.fix(0)
    1077           1 :         }
    1078           1 :         return nil
    1079             : }
    1080             : 
    1081             : // prevEntry steps to the previous entry.
    1082           1 : func (m *MergingIter) prevEntry() error {
    1083           1 :         l := &m.levels[m.heap.items[0].index]
    1084           1 :         if err := l.prev(); err != nil {
    1085           0 :                 return err
    1086           0 :         }
    1087           1 :         if !l.heapKey.valid() {
    1088           1 :                 // l.iter is exhausted.
    1089           1 :                 m.heap.pop()
    1090           1 :                 return nil
    1091           1 :         }
    1092             : 
    1093           1 :         if m.heap.len() > 1 {
    1094           1 :                 m.heap.fix(0)
    1095           1 :         }
    1096           1 :         return nil
    1097             : }
    1098             : 
    1099             : // DebugString returns a string representing the current internal state of the
    1100             : // merging iterator and its heap for debugging purposes.
    1101           0 : func (m *MergingIter) DebugString() string {
    1102           0 :         var buf bytes.Buffer
    1103           0 :         fmt.Fprintf(&buf, "Current bounds: [%q, %q)\n", m.start, m.end)
    1104           0 :         for i := range m.levels {
    1105           0 :                 fmt.Fprintf(&buf, "%d: heap key %s\n", i, m.levels[i].heapKey)
    1106           0 :         }
    1107           0 :         return buf.String()
    1108             : }
    1109             : 
    1110             : // WrapChildren implements FragmentIterator.
    1111           0 : func (m *MergingIter) WrapChildren(wrap keyspan.WrapFn) {
    1112           0 :         for i := range m.levels {
    1113           0 :                 m.levels[i].iter = wrap(m.levels[i].iter)
    1114           0 :         }
    1115           0 :         m.wrapFn = wrap
    1116             : }
    1117             : 
    1118             : // DebugTree is part of the FragmentIterator interface.
    1119           0 : func (m *MergingIter) DebugTree(tp treeprinter.Node) {
    1120           0 :         n := tp.Childf("%T(%p)", m, m)
    1121           0 :         for i := range m.levels {
    1122           0 :                 if iter := m.levels[i].iter; iter != nil {
    1123           0 :                         m.levels[i].iter.DebugTree(n)
    1124           0 :                 }
    1125             :         }
    1126             : }
    1127             : 
    1128             : type mergingIterItem struct {
    1129             :         // boundKey points to the corresponding mergingIterLevel's `iterKey`.
    1130             :         *boundKey
    1131             :         // index is the index of this level within the MergingIter's levels field.
    1132             :         index int
    1133             : }
    1134             : 
    1135             : // mergingIterHeap is copied from mergingIterHeap defined in the root pebble
    1136             : // package for use with point keys.
    1137             : 
    1138             : type mergingIterHeap struct {
    1139             :         cmp     base.Compare
    1140             :         reverse bool
    1141             :         items   []mergingIterItem
    1142             : }
    1143             : 
    1144           1 : func (h *mergingIterHeap) len() int {
    1145           1 :         return len(h.items)
    1146           1 : }
    1147             : 
    1148           1 : func (h *mergingIterHeap) less(i, j int) bool {
    1149           1 :         // This key comparison only uses the user key and not the boundKind. Bound
    1150           1 :         // kind doesn't matter because when stepping over a user key,
    1151           1 :         // findNextFragmentSet and findPrevFragmentSet skip past all heap items with
    1152           1 :         // that user key, and makes no assumptions on ordering. All other heap
    1153           1 :         // examinations only consider the user key.
    1154           1 :         ik, jk := h.items[i].key, h.items[j].key
    1155           1 :         c := h.cmp(ik, jk)
    1156           1 :         if h.reverse {
    1157           1 :                 return c > 0
    1158           1 :         }
    1159           1 :         return c < 0
    1160             : }
    1161             : 
    1162           1 : func (h *mergingIterHeap) swap(i, j int) {
    1163           1 :         h.items[i], h.items[j] = h.items[j], h.items[i]
    1164           1 : }
    1165             : 
    1166             : // init, fix, up and down are copied from the go stdlib.
    1167           1 : func (h *mergingIterHeap) init() {
    1168           1 :         // heapify
    1169           1 :         n := h.len()
    1170           1 :         for i := n/2 - 1; i >= 0; i-- {
    1171           1 :                 h.down(i, n)
    1172           1 :         }
    1173             : }
    1174             : 
    1175           1 : func (h *mergingIterHeap) fix(i int) {
    1176           1 :         if !h.down(i, h.len()) {
    1177           1 :                 h.up(i)
    1178           1 :         }
    1179             : }
    1180             : 
    1181           1 : func (h *mergingIterHeap) pop() *mergingIterItem {
    1182           1 :         n := h.len() - 1
    1183           1 :         h.swap(0, n)
    1184           1 :         h.down(0, n)
    1185           1 :         item := &h.items[n]
    1186           1 :         h.items = h.items[:n]
    1187           1 :         return item
    1188           1 : }
    1189             : 
    1190           1 : func (h *mergingIterHeap) up(j int) {
    1191           1 :         for {
    1192           1 :                 i := (j - 1) / 2 // parent
    1193           1 :                 if i == j || !h.less(j, i) {
    1194           1 :                         break
    1195             :                 }
    1196           0 :                 h.swap(i, j)
    1197           0 :                 j = i
    1198             :         }
    1199             : }
    1200             : 
    1201           1 : func (h *mergingIterHeap) down(i0, n int) bool {
    1202           1 :         i := i0
    1203           1 :         for {
    1204           1 :                 j1 := 2*i + 1
    1205           1 :                 if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
    1206           1 :                         break
    1207             :                 }
    1208           1 :                 j := j1 // left child
    1209           1 :                 if j2 := j1 + 1; j2 < n && h.less(j2, j1) {
    1210           1 :                         j = j2 // = 2*i + 2  // right child
    1211           1 :                 }
    1212           1 :                 if !h.less(j, i) {
    1213           1 :                         break
    1214             :                 }
    1215           1 :                 h.swap(i, j)
    1216           1 :                 i = j
    1217             :         }
    1218           1 :         return i > i0
    1219             : }
    1220             : 
    1221             : type boundKind int8
    1222             : 
    1223             : const (
    1224             :         boundKindInvalid boundKind = iota
    1225             :         boundKindFragmentStart
    1226             :         boundKindFragmentEnd
    1227             : )
    1228             : 
    1229             : type boundKey struct {
    1230             :         kind boundKind
    1231             :         key  []byte
    1232             :         // span holds the span the bound key comes from.
    1233             :         //
    1234             :         // If kind is boundKindFragmentStart, then key is span.Start. If kind is
    1235             :         // boundKindFragmentEnd, then key is span.End.
    1236             :         span *keyspan.Span
    1237             : }
    1238             : 
    1239           1 : func (k boundKey) valid() bool {
    1240           1 :         return k.kind != boundKindInvalid
    1241           1 : }
    1242             : 
    1243           0 : func (k boundKey) String() string {
    1244           0 :         var buf bytes.Buffer
    1245           0 :         switch k.kind {
    1246           0 :         case boundKindInvalid:
    1247           0 :                 fmt.Fprint(&buf, "invalid")
    1248           0 :         case boundKindFragmentStart:
    1249           0 :                 fmt.Fprint(&buf, "fragment-start")
    1250           0 :         case boundKindFragmentEnd:
    1251           0 :                 fmt.Fprint(&buf, "fragment-end  ")
    1252           0 :         default:
    1253           0 :                 fmt.Fprintf(&buf, "unknown-kind(%d)", k.kind)
    1254             :         }
    1255           0 :         fmt.Fprintf(&buf, " %s [", k.key)
    1256           0 :         fmt.Fprintf(&buf, "%s", k.span)
    1257           0 :         fmt.Fprint(&buf, "]")
    1258           0 :         return buf.String()
    1259             : }

Generated by: LCOV version 1.14