LCOV - code coverage report
Current view: top level - pebble/internal/keyspan/keyspanimpl - level_iter.go (source / functions) Hit Total Coverage
Test: 2024-02-25 08:15Z 0b946194 - tests + meta.lcov Lines: 333 376 88.6 %
Date: 2024-02-25 08:16:32 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             :         "fmt"
       9             : 
      10             :         "github.com/cockroachdb/errors"
      11             :         "github.com/cockroachdb/pebble/internal/base"
      12             :         "github.com/cockroachdb/pebble/internal/invariants"
      13             :         "github.com/cockroachdb/pebble/internal/keyspan"
      14             :         "github.com/cockroachdb/pebble/internal/manifest"
      15             : )
      16             : 
      17             : // TableNewSpanIter creates a new iterator for range key spans for the given
      18             : // file.
      19             : type TableNewSpanIter func(
      20             :         file *manifest.FileMetadata, iterOptions keyspan.SpanIterOptions,
      21             : ) (keyspan.FragmentIterator, error)
      22             : 
      23             : // LevelIter provides a merged view of spans from sstables in a level.
      24             : // It takes advantage of level invariants to only have one sstable span block
      25             : // open at one time, opened using the newIter function passed in.
      26             : type LevelIter struct {
      27             :         cmp base.Compare
      28             :         // Denotes the kind of key the level iterator should read. If the key type
      29             :         // is KeyTypePoint, the level iterator will read range tombstones (which
      30             :         // only affect point keys). If the key type is KeyTypeRange, the level
      31             :         // iterator will read range keys. It is invalid to configure an iterator
      32             :         // with the KeyTypePointAndRange key type.
      33             :         //
      34             :         // If key type is KeyTypePoint, no straddle spans are emitted between files,
      35             :         // and point key bounds are used to find files instead of range key bounds.
      36             :         //
      37             :         // TODO(bilal): Straddle spans can safely be produced in rangedel mode once
      38             :         // we can guarantee that we will never read sstables in a level that split
      39             :         // user keys across them. This might be guaranteed in a future release, but
      40             :         // as of CockroachDB 22.2 it is not guaranteed, so to be safe disable it when
      41             :         // keyType == KeyTypePoint
      42             :         keyType manifest.KeyType
      43             :         // The LSM level this LevelIter is initialized for. Used in logging.
      44             :         level manifest.Level
      45             :         // The below fields are used to fill in gaps between adjacent files' range
      46             :         // key spaces. This is an optimization to avoid unnecessarily loading files
      47             :         // in cases where range keys are sparse and rare. dir is set by every
      48             :         // positioning operation, straddleDir is set to dir whenever a straddling
      49             :         // Span is synthesized and the last positioning operation returned a
      50             :         // synthesized straddle span.
      51             :         //
      52             :         // Note that when a straddle span is initialized, iterFile is modified to
      53             :         // point to the next file in the straddleDir direction. A change of direction
      54             :         // on a straddle key therefore necessitates the value of iterFile to be
      55             :         // reverted.
      56             :         dir         int
      57             :         straddle    keyspan.Span
      58             :         straddleDir int
      59             :         // The iter for the current file (iterFile). It is nil under any of the
      60             :         // following conditions:
      61             :         // - files.Current() == nil
      62             :         // - err != nil
      63             :         // - straddleDir != 0, in which case iterFile is not nil and points to the
      64             :         //   next file (in the straddleDir direction).
      65             :         // - some other constraint, like the bounds in opts, caused the file at index to not
      66             :         //   be relevant to the iteration.
      67             :         iter   keyspan.FragmentIterator
      68             :         wrapFn keyspan.WrapFn
      69             :         // iterFile holds the current file.
      70             :         // INVARIANT: iterFile = files.Current()
      71             :         iterFile *manifest.FileMetadata
      72             :         newIter  TableNewSpanIter
      73             :         files    manifest.LevelIterator
      74             :         err      error
      75             : 
      76             :         // The options that were passed in.
      77             :         tableOpts keyspan.SpanIterOptions
      78             : 
      79             :         // TODO(bilal): Add InternalIteratorStats.
      80             : }
      81             : 
      82             : // LevelIter implements the keyspan.FragmentIterator interface.
      83             : var _ keyspan.FragmentIterator = (*LevelIter)(nil)
      84             : 
      85             : // NewLevelIter returns a LevelIter.
      86             : func NewLevelIter(
      87             :         opts keyspan.SpanIterOptions,
      88             :         cmp base.Compare,
      89             :         newIter TableNewSpanIter,
      90             :         files manifest.LevelIterator,
      91             :         level manifest.Level,
      92             :         keyType manifest.KeyType,
      93           2 : ) *LevelIter {
      94           2 :         l := &LevelIter{}
      95           2 :         l.Init(opts, cmp, newIter, files, level, keyType)
      96           2 :         return l
      97           2 : }
      98             : 
      99             : // Init initializes a LevelIter.
     100             : func (l *LevelIter) Init(
     101             :         opts keyspan.SpanIterOptions,
     102             :         cmp base.Compare,
     103             :         newIter TableNewSpanIter,
     104             :         files manifest.LevelIterator,
     105             :         level manifest.Level,
     106             :         keyType manifest.KeyType,
     107           2 : ) {
     108           2 :         l.err = nil
     109           2 :         l.level = level
     110           2 :         l.tableOpts = opts
     111           2 :         l.cmp = cmp
     112           2 :         l.iterFile = nil
     113           2 :         l.newIter = newIter
     114           2 :         switch keyType {
     115           2 :         case manifest.KeyTypePoint:
     116           2 :                 l.keyType = keyType
     117           2 :                 l.files = files.Filter(keyType)
     118           2 :         case manifest.KeyTypeRange:
     119           2 :                 l.keyType = keyType
     120           2 :                 l.files = files.Filter(keyType)
     121           0 :         default:
     122           0 :                 panic(fmt.Sprintf("unsupported key type: %v", keyType))
     123             :         }
     124             : }
     125             : 
     126           2 : func (l *LevelIter) findFileGE(key []byte) *manifest.FileMetadata {
     127           2 :         // Find the earliest file whose largest key is >= key.
     128           2 :         //
     129           2 :         // If the earliest file has its largest key == key and that largest key is a
     130           2 :         // range deletion sentinel, we know that we manufactured this sentinel to convert
     131           2 :         // the exclusive range deletion end key into an inclusive key (reminder: [start, end)#seqnum
     132           2 :         // is the form of a range deletion sentinel which can contribute a largest key = end#sentinel).
     133           2 :         // In this case we don't return this as the earliest file since there is nothing actually
     134           2 :         // equal to key in it.
     135           2 : 
     136           2 :         m := l.files.SeekGE(l.cmp, key)
     137           2 :         for m != nil {
     138           2 :                 largestKey := m.LargestRangeKey
     139           2 :                 if l.keyType == manifest.KeyTypePoint {
     140           2 :                         largestKey = m.LargestPointKey
     141           2 :                 }
     142           2 :                 if !largestKey.IsExclusiveSentinel() || l.cmp(largestKey.UserKey, key) != 0 {
     143           2 :                         break
     144             :                 }
     145           0 :                 m = l.files.Next()
     146             :         }
     147           2 :         return m
     148             : }
     149             : 
     150           2 : func (l *LevelIter) findFileLT(key []byte) *manifest.FileMetadata {
     151           2 :         // Find the last file whose smallest key is < key.
     152           2 :         return l.files.SeekLT(l.cmp, key)
     153           2 : }
     154             : 
     155             : type loadFileReturnIndicator int8
     156             : 
     157             : const (
     158             :         noFileLoaded loadFileReturnIndicator = iota
     159             :         fileAlreadyLoaded
     160             :         newFileLoaded
     161             : )
     162             : 
     163           2 : func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileReturnIndicator {
     164           2 :         indicator := noFileLoaded
     165           2 :         if l.iterFile == file {
     166           2 :                 if l.err != nil {
     167           0 :                         return noFileLoaded
     168           0 :                 }
     169           2 :                 if l.iter != nil {
     170           2 :                         // We are already at the file, but we would need to check for bounds.
     171           2 :                         // Set indicator accordingly.
     172           2 :                         indicator = fileAlreadyLoaded
     173           2 :                 }
     174             :                 // We were already at file, but don't have an iterator, probably because the file was
     175             :                 // beyond the iteration bounds. It may still be, but it is also possible that the bounds
     176             :                 // have changed. We handle that below.
     177             :         }
     178             : 
     179             :         // Note that LevelIter.Close() can be called multiple times.
     180           2 :         if indicator != fileAlreadyLoaded {
     181           2 :                 if err := l.Close(); err != nil {
     182           0 :                         return noFileLoaded
     183           0 :                 }
     184             :         }
     185             : 
     186           2 :         l.iterFile = file
     187           2 :         if file == nil {
     188           2 :                 return noFileLoaded
     189           2 :         }
     190           2 :         if indicator != fileAlreadyLoaded {
     191           2 :                 l.iter, l.err = l.newIter(file, l.tableOpts)
     192           2 :                 if l.wrapFn != nil {
     193           0 :                         l.iter = l.wrapFn(l.iter)
     194           0 :                 }
     195           2 :                 l.iter = keyspan.MaybeAssert(l.iter, l.cmp)
     196           2 :                 indicator = newFileLoaded
     197             :         }
     198           2 :         if l.err != nil {
     199           1 :                 return noFileLoaded
     200           1 :         }
     201           2 :         return indicator
     202             : }
     203             : 
     204             : // SeekGE implements keyspan.FragmentIterator.
     205           2 : func (l *LevelIter) SeekGE(key []byte) (*keyspan.Span, error) {
     206           2 :         l.dir = +1
     207           2 :         l.straddle = keyspan.Span{}
     208           2 :         l.straddleDir = 0
     209           2 :         l.err = nil // clear cached iteration error
     210           2 : 
     211           2 :         f := l.findFileGE(key)
     212           2 :         if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(key, f.SmallestRangeKey.UserKey) < 0 {
     213           2 :                 // Peek at the previous file.
     214           2 :                 prevFile := l.files.Prev()
     215           2 :                 l.files.Next()
     216           2 :                 if prevFile != nil {
     217           2 :                         // We could unconditionally return an empty span between the seek key and
     218           2 :                         // f.SmallestRangeKey, however if this span is to the left of all range
     219           2 :                         // keys on this level, it could lead to inconsistent behaviour in relative
     220           2 :                         // positioning operations. Consider this example, with a b-c range key:
     221           2 :                         //
     222           2 :                         // SeekGE(a) -> a-b:{}
     223           2 :                         // Next() -> b-c{(#5,RANGEKEYSET,@4,foo)}
     224           2 :                         // Prev() -> nil
     225           2 :                         //
     226           2 :                         // Iterators higher up in the iterator stack rely on this sort of relative
     227           2 :                         // positioning consistency.
     228           2 :                         //
     229           2 :                         // TODO(bilal): Investigate ways to be able to return straddle spans in
     230           2 :                         // cases similar to the above, while still retaining correctness.
     231           2 :                         // Return a straddling key instead of loading the file.
     232           2 :                         l.iterFile = f
     233           2 :                         if l.err = l.Close(); l.err != nil {
     234           0 :                                 return l.verify(nil, l.err)
     235           0 :                         }
     236           2 :                         l.straddleDir = +1
     237           2 :                         l.straddle = keyspan.Span{
     238           2 :                                 Start: prevFile.LargestRangeKey.UserKey,
     239           2 :                                 End:   f.SmallestRangeKey.UserKey,
     240           2 :                                 Keys:  nil,
     241           2 :                         }
     242           2 :                         return l.verify(&l.straddle, nil)
     243             :                 }
     244             :         }
     245           2 :         loadFileIndicator := l.loadFile(f, +1)
     246           2 :         if loadFileIndicator == noFileLoaded {
     247           2 :                 return l.verify(nil, l.err)
     248           2 :         }
     249           2 :         if span, err := l.iter.SeekGE(key); err != nil {
     250           0 :                 return l.verify(nil, err)
     251           2 :         } else if span != nil {
     252           2 :                 return l.verify(span, nil)
     253           2 :         }
     254           2 :         return l.skipEmptyFileForward()
     255             : }
     256             : 
     257             : // SeekLT implements keyspan.FragmentIterator.
     258           2 : func (l *LevelIter) SeekLT(key []byte) (*keyspan.Span, error) {
     259           2 :         l.dir = -1
     260           2 :         l.straddle = keyspan.Span{}
     261           2 :         l.straddleDir = 0
     262           2 :         l.err = nil // clear cached iteration error
     263           2 : 
     264           2 :         f := l.findFileLT(key)
     265           2 :         if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(f.LargestRangeKey.UserKey, key) < 0 {
     266           2 :                 // Peek at the next file.
     267           2 :                 nextFile := l.files.Next()
     268           2 :                 l.files.Prev()
     269           2 :                 if nextFile != nil {
     270           2 :                         // We could unconditionally return an empty span between f.LargestRangeKey
     271           2 :                         // and the seek key, however if this span is to the right of all range keys
     272           2 :                         // on this level, it could lead to inconsistent behaviour in relative
     273           2 :                         // positioning operations. Consider this example, with a b-c range key:
     274           2 :                         //
     275           2 :                         // SeekLT(d) -> c-d:{}
     276           2 :                         // Prev() -> b-c{(#5,RANGEKEYSET,@4,foo)}
     277           2 :                         // Next() -> nil
     278           2 :                         //
     279           2 :                         // Iterators higher up in the iterator stack rely on this sort of relative
     280           2 :                         // positioning consistency.
     281           2 :                         //
     282           2 :                         // TODO(bilal): Investigate ways to be able to return straddle spans in
     283           2 :                         // cases similar to the above, while still retaining correctness.
     284           2 :                         // Return a straddling key instead of loading the file.
     285           2 :                         l.iterFile = f
     286           2 :                         if l.err = l.Close(); l.err != nil {
     287           0 :                                 return l.verify(nil, l.err)
     288           0 :                         }
     289           2 :                         l.straddleDir = -1
     290           2 :                         l.straddle = keyspan.Span{
     291           2 :                                 Start: f.LargestRangeKey.UserKey,
     292           2 :                                 End:   nextFile.SmallestRangeKey.UserKey,
     293           2 :                                 Keys:  nil,
     294           2 :                         }
     295           2 :                         return l.verify(&l.straddle, nil)
     296             :                 }
     297             :         }
     298           2 :         if l.loadFile(f, -1) == noFileLoaded {
     299           2 :                 return l.verify(nil, l.err)
     300           2 :         }
     301           2 :         if span, err := l.iter.SeekLT(key); err != nil {
     302           0 :                 return l.verify(nil, err)
     303           2 :         } else if span != nil {
     304           2 :                 return l.verify(span, nil)
     305           2 :         }
     306           2 :         return l.skipEmptyFileBackward()
     307             : }
     308             : 
     309             : // First implements keyspan.FragmentIterator.
     310           2 : func (l *LevelIter) First() (*keyspan.Span, error) {
     311           2 :         l.dir = +1
     312           2 :         l.straddle = keyspan.Span{}
     313           2 :         l.straddleDir = 0
     314           2 :         l.err = nil // clear cached iteration error
     315           2 : 
     316           2 :         if l.loadFile(l.files.First(), +1) == noFileLoaded {
     317           2 :                 return l.verify(nil, l.err)
     318           2 :         }
     319           2 :         if span, err := l.iter.First(); err != nil {
     320           0 :                 return l.verify(nil, err)
     321           2 :         } else if span != nil {
     322           2 :                 return l.verify(span, nil)
     323           2 :         }
     324           2 :         return l.skipEmptyFileForward()
     325             : }
     326             : 
     327             : // Last implements keyspan.FragmentIterator.
     328           2 : func (l *LevelIter) Last() (*keyspan.Span, error) {
     329           2 :         l.dir = -1
     330           2 :         l.straddle = keyspan.Span{}
     331           2 :         l.straddleDir = 0
     332           2 :         l.err = nil // clear cached iteration error
     333           2 : 
     334           2 :         if l.loadFile(l.files.Last(), -1) == noFileLoaded {
     335           2 :                 return l.verify(nil, l.err)
     336           2 :         }
     337           2 :         if span, err := l.iter.Last(); err != nil {
     338           0 :                 return l.verify(nil, err)
     339           2 :         } else if span != nil {
     340           2 :                 return l.verify(span, nil)
     341           2 :         }
     342           2 :         return l.skipEmptyFileBackward()
     343             : }
     344             : 
     345             : // Next implements keyspan.FragmentIterator.
     346           2 : func (l *LevelIter) Next() (*keyspan.Span, error) {
     347           2 :         if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir > 0) {
     348           1 :                 return l.verify(nil, l.err)
     349           1 :         }
     350           2 :         if l.iter == nil && l.iterFile == nil {
     351           2 :                 // l.dir <= 0
     352           2 :                 return l.First()
     353           2 :         }
     354           2 :         l.dir = +1
     355           2 : 
     356           2 :         if l.iter != nil {
     357           2 :                 if span, err := l.iter.Next(); err != nil {
     358           0 :                         return l.verify(nil, err)
     359           2 :                 } else if span != nil {
     360           2 :                         return l.verify(span, nil)
     361           2 :                 }
     362             :         }
     363           2 :         return l.skipEmptyFileForward()
     364             : }
     365             : 
     366             : // Prev implements keyspan.FragmentIterator.
     367           2 : func (l *LevelIter) Prev() (*keyspan.Span, error) {
     368           2 :         if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir < 0) {
     369           1 :                 return l.verify(nil, l.err)
     370           1 :         }
     371           2 :         if l.iter == nil && l.iterFile == nil {
     372           2 :                 // l.dir >= 0
     373           2 :                 return l.Last()
     374           2 :         }
     375           2 :         l.dir = -1
     376           2 : 
     377           2 :         if l.iter != nil {
     378           2 :                 if span, err := l.iter.Prev(); err != nil {
     379           0 :                         return nil, err
     380           2 :                 } else if span != nil {
     381           2 :                         return l.verify(span, nil)
     382           2 :                 }
     383             :         }
     384           2 :         return l.skipEmptyFileBackward()
     385             : }
     386             : 
     387           2 : func (l *LevelIter) skipEmptyFileForward() (*keyspan.Span, error) {
     388           2 :         if l.straddleDir == 0 && l.keyType == manifest.KeyTypeRange &&
     389           2 :                 l.iterFile != nil && l.iter != nil {
     390           2 :                 // We were at a file that had spans. Check if the next file that has
     391           2 :                 // spans is not directly adjacent to the current file i.e. there is a
     392           2 :                 // gap in the span keyspace between the two files. In that case, synthesize
     393           2 :                 // a "straddle span" in l.straddle and return that.
     394           2 :                 //
     395           2 :                 // Straddle spans are not created in rangedel mode.
     396           2 :                 if l.err = l.Close(); l.err != nil {
     397           0 :                         return l.verify(nil, l.err)
     398           0 :                 }
     399           2 :                 startKey := l.iterFile.LargestRangeKey.UserKey
     400           2 :                 // Resetting l.iterFile without loading the file into l.iter is okay and
     401           2 :                 // does not change the logic in loadFile() as long as l.iter is also nil;
     402           2 :                 // which it should be due to the Close() call above.
     403           2 :                 l.iterFile = l.files.Next()
     404           2 :                 if l.iterFile == nil {
     405           2 :                         return l.verify(nil, nil)
     406           2 :                 }
     407           2 :                 endKey := l.iterFile.SmallestRangeKey.UserKey
     408           2 :                 if l.cmp(startKey, endKey) < 0 {
     409           2 :                         // There is a gap between the two files. Synthesize a straddling span
     410           2 :                         // to avoid unnecessarily loading the next file.
     411           2 :                         l.straddle = keyspan.Span{
     412           2 :                                 Start: startKey,
     413           2 :                                 End:   endKey,
     414           2 :                         }
     415           2 :                         l.straddleDir = +1
     416           2 :                         return l.verify(&l.straddle, nil)
     417           2 :                 }
     418           2 :         } else if l.straddleDir < 0 {
     419           2 :                 // We were at a straddle key, but are now changing directions. l.iterFile
     420           2 :                 // was already moved backward by skipEmptyFileBackward, so advance it
     421           2 :                 // forward.
     422           2 :                 l.iterFile = l.files.Next()
     423           2 :         }
     424           2 :         l.straddle = keyspan.Span{}
     425           2 :         l.straddleDir = 0
     426           2 :         var span *keyspan.Span
     427           2 :         for span.Empty() {
     428           2 :                 fileToLoad := l.iterFile
     429           2 :                 if l.keyType == manifest.KeyTypePoint {
     430           2 :                         // We haven't iterated to the next file yet if we're in point key
     431           2 :                         // (rangedel) mode.
     432           2 :                         fileToLoad = l.files.Next()
     433           2 :                 }
     434           2 :                 if l.loadFile(fileToLoad, +1) == noFileLoaded {
     435           2 :                         return l.verify(nil, l.err)
     436           2 :                 }
     437           2 :                 span, l.err = l.iter.First()
     438           2 :                 if l.err != nil {
     439           0 :                         return l.verify(nil, l.err)
     440           0 :                 }
     441             :                 // In rangedel mode, we can expect to get empty files that we'd need to
     442             :                 // skip over, but not in range key mode.
     443           2 :                 if l.keyType == manifest.KeyTypeRange {
     444           2 :                         break
     445             :                 }
     446             :         }
     447           2 :         return l.verify(span, l.err)
     448             : }
     449             : 
     450           2 : func (l *LevelIter) skipEmptyFileBackward() (*keyspan.Span, error) {
     451           2 :         // We were at a file that had spans. Check if the previous file that has
     452           2 :         // spans is not directly adjacent to the current file i.e. there is a
     453           2 :         // gap in the span keyspace between the two files. In that case, synthesize
     454           2 :         // a "straddle span" in l.straddle and return that.
     455           2 :         //
     456           2 :         // Straddle spans are not created in rangedel mode.
     457           2 :         if l.straddleDir == 0 && l.keyType == manifest.KeyTypeRange &&
     458           2 :                 l.iterFile != nil && l.iter != nil {
     459           2 :                 if l.err = l.Close(); l.err != nil {
     460           0 :                         return l.verify(nil, l.err)
     461           0 :                 }
     462           2 :                 endKey := l.iterFile.SmallestRangeKey.UserKey
     463           2 :                 // Resetting l.iterFile without loading the file into l.iter is okay and
     464           2 :                 // does not change the logic in loadFile() as long as l.iter is also nil;
     465           2 :                 // which it should be due to the Close() call above.
     466           2 :                 l.iterFile = l.files.Prev()
     467           2 :                 if l.iterFile == nil {
     468           2 :                         return l.verify(nil, nil)
     469           2 :                 }
     470           2 :                 startKey := l.iterFile.LargestRangeKey.UserKey
     471           2 :                 if l.cmp(startKey, endKey) < 0 {
     472           2 :                         // There is a gap between the two files. Synthesize a straddling span
     473           2 :                         // to avoid unnecessarily loading the next file.
     474           2 :                         l.straddle = keyspan.Span{
     475           2 :                                 Start: startKey,
     476           2 :                                 End:   endKey,
     477           2 :                         }
     478           2 :                         l.straddleDir = -1
     479           2 :                         return l.verify(&l.straddle, nil)
     480           2 :                 }
     481           2 :         } else if l.straddleDir > 0 {
     482           2 :                 // We were at a straddle key, but are now changing directions. l.iterFile
     483           2 :                 // was already advanced forward by skipEmptyFileForward, so move it
     484           2 :                 // backward.
     485           2 :                 l.iterFile = l.files.Prev()
     486           2 :         }
     487           2 :         l.straddle = keyspan.Span{}
     488           2 :         l.straddleDir = 0
     489           2 :         var span *keyspan.Span
     490           2 :         for span.Empty() {
     491           2 :                 fileToLoad := l.iterFile
     492           2 :                 if l.keyType == manifest.KeyTypePoint {
     493           2 :                         fileToLoad = l.files.Prev()
     494           2 :                 }
     495           2 :                 if l.loadFile(fileToLoad, -1) == noFileLoaded {
     496           2 :                         return l.verify(nil, l.err)
     497           2 :                 }
     498           2 :                 span, l.err = l.iter.Last()
     499           2 :                 if l.err != nil {
     500           0 :                         return l.verify(span, l.err)
     501           0 :                 }
     502             :                 // In rangedel mode, we can expect to get empty files that we'd need to
     503             :                 // skip over, but not in range key mode as the filter on the FileMetadata
     504             :                 // should guarantee we always get a non-empty file.
     505           2 :                 if l.keyType == manifest.KeyTypeRange {
     506           2 :                         break
     507             :                 }
     508             :         }
     509           2 :         return l.verify(span, l.err)
     510             : }
     511             : 
     512             : // verify is invoked whenever a span is returned from an iterator positioning
     513             : // method to a caller. During invariant builds, it asserts invariants to the
     514             : // caller.
     515           2 : func (l *LevelIter) verify(s *keyspan.Span, err error) (*keyspan.Span, error) {
     516           2 :         // NB: Do not add any logic outside the invariants.Enabled conditional to
     517           2 :         // ensure that verify is always compiled away in production builds.
     518           2 :         if invariants.Enabled {
     519           2 :                 if err != l.err {
     520           0 :                         panic(errors.AssertionFailedf("LevelIter.err (%v) != returned error (%v)", l.err, err))
     521             :                 }
     522           2 :                 if err != nil && s != nil {
     523           0 :                         panic(errors.AssertionFailedf("non-nil error returned alongside non-nil span"))
     524             :                 }
     525           2 :                 if f := l.files.Current(); f != l.iterFile {
     526           0 :                         panic(fmt.Sprintf("LevelIter.files.Current (%s) and l.iterFile (%s) diverged",
     527           0 :                                 f, l.iterFile))
     528             :                 }
     529             :         }
     530           2 :         return s, err
     531             : }
     532             : 
     533             : // Error implements keyspan.FragmentIterator.
     534           0 : func (l *LevelIter) Error() error {
     535           0 :         return l.err
     536           0 : }
     537             : 
     538             : // Close implements keyspan.FragmentIterator.
     539           2 : func (l *LevelIter) Close() error {
     540           2 :         if l.iter != nil {
     541           2 :                 l.err = l.iter.Close()
     542           2 :                 l.iter = nil
     543           2 :         }
     544           2 :         return l.err
     545             : }
     546             : 
     547             : // String implements keyspan.FragmentIterator.
     548           0 : func (l *LevelIter) String() string {
     549           0 :         if l.iterFile != nil {
     550           0 :                 return fmt.Sprintf("%s: fileNum=%s", l.level, l.iterFile.FileNum)
     551           0 :         }
     552           0 :         return fmt.Sprintf("%s: fileNum=<nil>", l.level)
     553             : }
     554             : 
     555             : // WrapChildren implements FragmentIterator.
     556           0 : func (l *LevelIter) WrapChildren(wrap keyspan.WrapFn) {
     557           0 :         l.iter = wrap(l.iter)
     558           0 :         l.wrapFn = wrap
     559           0 : }

Generated by: LCOV version 1.14