LCOV - code coverage report
Current view: top level - pebble - get_iter.go (source / functions) Hit Total Coverage
Test: 2023-10-14 08:17Z bbbf3df1 - meta test only.lcov Lines: 116 149 77.9 %
Date: 2023-10-14 08:18:03 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2018 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 pebble
       6             : 
       7             : import (
       8             :         "context"
       9             :         "fmt"
      10             : 
      11             :         "github.com/cockroachdb/pebble/internal/base"
      12             :         "github.com/cockroachdb/pebble/internal/keyspan"
      13             :         "github.com/cockroachdb/pebble/internal/manifest"
      14             : )
      15             : 
      16             : // getIter is an internal iterator used to perform gets. It iterates through
      17             : // the values for a particular key, level by level. It is not a general purpose
      18             : // internalIterator, but specialized for Get operations so that it loads data
      19             : // lazily.
      20             : type getIter struct {
      21             :         logger       Logger
      22             :         comparer     *Comparer
      23             :         newIters     tableNewIters
      24             :         snapshot     uint64
      25             :         key          []byte
      26             :         iter         internalIterator
      27             :         rangeDelIter keyspan.FragmentIterator
      28             :         tombstone    *keyspan.Span
      29             :         levelIter    levelIter
      30             :         level        int
      31             :         batch        *Batch
      32             :         mem          flushableList
      33             :         l0           []manifest.LevelSlice
      34             :         version      *version
      35             :         iterKey      *InternalKey
      36             :         iterValue    base.LazyValue
      37             :         err          error
      38             : }
      39             : 
      40             : // TODO(sumeer): CockroachDB code doesn't use getIter, but, for completeness,
      41             : // make this implement InternalIteratorWithStats.
      42             : 
      43             : // getIter implements the base.InternalIterator interface.
      44             : var _ base.InternalIterator = (*getIter)(nil)
      45             : 
      46           0 : func (g *getIter) String() string {
      47           0 :         return fmt.Sprintf("len(l0)=%d, len(mem)=%d, level=%d", len(g.l0), len(g.mem), g.level)
      48           0 : }
      49             : 
      50           0 : func (g *getIter) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, base.LazyValue) {
      51           0 :         panic("pebble: SeekGE unimplemented")
      52             : }
      53             : 
      54             : func (g *getIter) SeekPrefixGE(
      55             :         prefix, key []byte, flags base.SeekGEFlags,
      56           0 : ) (*base.InternalKey, base.LazyValue) {
      57           0 :         panic("pebble: SeekPrefixGE unimplemented")
      58             : }
      59             : 
      60           0 : func (g *getIter) SeekLT(key []byte, flags base.SeekLTFlags) (*InternalKey, base.LazyValue) {
      61           0 :         panic("pebble: SeekLT unimplemented")
      62             : }
      63             : 
      64           1 : func (g *getIter) First() (*InternalKey, base.LazyValue) {
      65           1 :         return g.Next()
      66           1 : }
      67             : 
      68           0 : func (g *getIter) Last() (*InternalKey, base.LazyValue) {
      69           0 :         panic("pebble: Last unimplemented")
      70             : }
      71             : 
      72           1 : func (g *getIter) Next() (*InternalKey, base.LazyValue) {
      73           1 :         if g.iter != nil {
      74           1 :                 g.iterKey, g.iterValue = g.iter.Next()
      75           1 :         }
      76             : 
      77           1 :         for {
      78           1 :                 if g.iter != nil {
      79           1 :                         // We have to check rangeDelIter on each iteration because a single
      80           1 :                         // user-key can be spread across multiple tables in a level. A range
      81           1 :                         // tombstone will appear in the table corresponding to its start
      82           1 :                         // key. Every call to levelIter.Next() potentially switches to a new
      83           1 :                         // table and thus reinitializes rangeDelIter.
      84           1 :                         if g.rangeDelIter != nil {
      85           1 :                                 g.tombstone = keyspan.Get(g.comparer.Compare, g.rangeDelIter, g.key)
      86           1 :                                 if g.err = g.rangeDelIter.Close(); g.err != nil {
      87           0 :                                         return nil, base.LazyValue{}
      88           0 :                                 }
      89           1 :                                 g.rangeDelIter = nil
      90             :                         }
      91             : 
      92           1 :                         if g.iterKey != nil {
      93           1 :                                 key := g.iterKey
      94           1 :                                 if g.tombstone != nil && g.tombstone.CoversAt(g.snapshot, key.SeqNum()) {
      95           1 :                                         // We have a range tombstone covering this key. Rather than return a
      96           1 :                                         // point or range deletion here, we return false and close our
      97           1 :                                         // internal iterator which will make Valid() return false,
      98           1 :                                         // effectively stopping iteration.
      99           1 :                                         g.err = g.iter.Close()
     100           1 :                                         g.iter = nil
     101           1 :                                         return nil, base.LazyValue{}
     102           1 :                                 }
     103           1 :                                 if g.comparer.Equal(g.key, key.UserKey) {
     104           1 :                                         if !key.Visible(g.snapshot, base.InternalKeySeqNumMax) {
     105           1 :                                                 g.iterKey, g.iterValue = g.iter.Next()
     106           1 :                                                 continue
     107             :                                         }
     108           1 :                                         return g.iterKey, g.iterValue
     109             :                                 }
     110             :                         }
     111             :                         // We've advanced the iterator passed the desired key. Move on to the
     112             :                         // next memtable / level.
     113           1 :                         g.err = g.iter.Close()
     114           1 :                         g.iter = nil
     115           1 :                         if g.err != nil {
     116           0 :                                 return nil, base.LazyValue{}
     117           0 :                         }
     118             :                 }
     119             : 
     120             :                 // Create an iterator from the batch.
     121           1 :                 if g.batch != nil {
     122           1 :                         if g.batch.index == nil {
     123           0 :                                 g.err = ErrNotIndexed
     124           0 :                                 g.iterKey, g.iterValue = nil, base.LazyValue{}
     125           0 :                                 return nil, base.LazyValue{}
     126           0 :                         }
     127           1 :                         g.iter = g.batch.newInternalIter(nil)
     128           1 :                         g.rangeDelIter = g.batch.newRangeDelIter(
     129           1 :                                 nil,
     130           1 :                                 // Get always reads the entirety of the batch's history, so no
     131           1 :                                 // batch keys should be filtered.
     132           1 :                                 base.InternalKeySeqNumMax,
     133           1 :                         )
     134           1 :                         g.iterKey, g.iterValue = g.iter.SeekGE(g.key, base.SeekGEFlagsNone)
     135           1 :                         g.batch = nil
     136           1 :                         continue
     137             :                 }
     138             : 
     139             :                 // If we have a tombstone from a previous level it is guaranteed to delete
     140             :                 // keys in lower levels.
     141           1 :                 if g.tombstone != nil && g.tombstone.VisibleAt(g.snapshot) {
     142           1 :                         return nil, base.LazyValue{}
     143           1 :                 }
     144             : 
     145             :                 // Create iterators from memtables from newest to oldest.
     146           1 :                 if n := len(g.mem); n > 0 {
     147           1 :                         m := g.mem[n-1]
     148           1 :                         g.iter = m.newIter(nil)
     149           1 :                         g.rangeDelIter = m.newRangeDelIter(nil)
     150           1 :                         g.mem = g.mem[:n-1]
     151           1 :                         g.iterKey, g.iterValue = g.iter.SeekGE(g.key, base.SeekGEFlagsNone)
     152           1 :                         continue
     153             :                 }
     154             : 
     155           1 :                 if g.level == 0 {
     156           1 :                         // Create iterators from L0 from newest to oldest.
     157           1 :                         if n := len(g.l0); n > 0 {
     158           1 :                                 files := g.l0[n-1].Iter()
     159           1 :                                 g.l0 = g.l0[:n-1]
     160           1 :                                 iterOpts := IterOptions{logger: g.logger, snapshotForHideObsoletePoints: g.snapshot}
     161           1 :                                 g.levelIter.init(context.Background(), iterOpts, g.comparer, g.newIters,
     162           1 :                                         files, manifest.L0Sublevel(n), internalIterOpts{})
     163           1 :                                 g.levelIter.initRangeDel(&g.rangeDelIter)
     164           1 :                                 bc := levelIterBoundaryContext{}
     165           1 :                                 g.levelIter.initBoundaryContext(&bc)
     166           1 :                                 g.iter = &g.levelIter
     167           1 : 
     168           1 :                                 // Compute the key prefix for bloom filtering if split function is
     169           1 :                                 // specified, or use the user key as default.
     170           1 :                                 prefix := g.key
     171           1 :                                 if g.comparer.Split != nil {
     172           1 :                                         prefix = g.key[:g.comparer.Split(g.key)]
     173           1 :                                 }
     174           1 :                                 g.iterKey, g.iterValue = g.iter.SeekPrefixGE(prefix, g.key, base.SeekGEFlagsNone)
     175           1 :                                 if bc.isSyntheticIterBoundsKey || bc.isIgnorableBoundaryKey {
     176           1 :                                         g.iterKey = nil
     177           1 :                                         g.iterValue = base.LazyValue{}
     178           1 :                                 }
     179           1 :                                 continue
     180             :                         }
     181           1 :                         g.level++
     182             :                 }
     183             : 
     184           1 :                 if g.level >= numLevels {
     185           1 :                         return nil, base.LazyValue{}
     186           1 :                 }
     187           1 :                 if g.version.Levels[g.level].Empty() {
     188           1 :                         g.level++
     189           1 :                         continue
     190             :                 }
     191             : 
     192           1 :                 iterOpts := IterOptions{logger: g.logger, snapshotForHideObsoletePoints: g.snapshot}
     193           1 :                 g.levelIter.init(context.Background(), iterOpts, g.comparer, g.newIters,
     194           1 :                         g.version.Levels[g.level].Iter(), manifest.Level(g.level), internalIterOpts{})
     195           1 :                 g.levelIter.initRangeDel(&g.rangeDelIter)
     196           1 :                 bc := levelIterBoundaryContext{}
     197           1 :                 g.levelIter.initBoundaryContext(&bc)
     198           1 :                 g.level++
     199           1 :                 g.iter = &g.levelIter
     200           1 : 
     201           1 :                 // Compute the key prefix for bloom filtering if split function is
     202           1 :                 // specified, or use the user key as default.
     203           1 :                 prefix := g.key
     204           1 :                 if g.comparer.Split != nil {
     205           1 :                         prefix = g.key[:g.comparer.Split(g.key)]
     206           1 :                 }
     207           1 :                 g.iterKey, g.iterValue = g.iter.SeekPrefixGE(prefix, g.key, base.SeekGEFlagsNone)
     208           1 :                 if bc.isSyntheticIterBoundsKey || bc.isIgnorableBoundaryKey {
     209           1 :                         g.iterKey = nil
     210           1 :                         g.iterValue = base.LazyValue{}
     211           1 :                 }
     212             :         }
     213             : }
     214             : 
     215           0 : func (g *getIter) Prev() (*InternalKey, base.LazyValue) {
     216           0 :         panic("pebble: Prev unimplemented")
     217             : }
     218             : 
     219           0 : func (g *getIter) NextPrefix([]byte) (*InternalKey, base.LazyValue) {
     220           0 :         panic("pebble: NextPrefix unimplemented")
     221             : }
     222             : 
     223           0 : func (g *getIter) Valid() bool {
     224           0 :         return g.iterKey != nil && g.err == nil
     225           0 : }
     226             : 
     227           0 : func (g *getIter) Error() error {
     228           0 :         return g.err
     229           0 : }
     230             : 
     231           1 : func (g *getIter) Close() error {
     232           1 :         if g.iter != nil {
     233           1 :                 if err := g.iter.Close(); err != nil && g.err == nil {
     234           0 :                         g.err = err
     235           0 :                 }
     236           1 :                 g.iter = nil
     237             :         }
     238           1 :         return g.err
     239             : }
     240             : 
     241           0 : func (g *getIter) SetBounds(lower, upper []byte) {
     242           0 :         panic("pebble: SetBounds unimplemented")
     243             : }

Generated by: LCOV version 1.14