LCOV - code coverage report
Current view: top level - pebble/internal/keyspan - filter.go (source / functions) Hit Total Coverage
Test: 2024-02-12 08:16Z 38e3430f - meta test only.lcov Lines: 53 74 71.6 %
Date: 2024-02-12 08:17:11 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 keyspan
       6             : 
       7             : import "github.com/cockroachdb/pebble/internal/base"
       8             : 
       9             : // FilterFunc defines a transform from the input Span into the output Span. The
      10             : // function returns true if the Span should be returned by the iterator, and
      11             : // false if the Span should be skipped. The FilterFunc is permitted to mutate
      12             : // the output Span, for example, to elice certain keys, or update the Span's
      13             : // bounds if so desired. The output Span's Keys slice may be reused to reduce
      14             : // allocations.
      15             : type FilterFunc func(in *Span, out *Span) (keep bool)
      16             : 
      17             : // filteringIter is a FragmentIterator that uses a FilterFunc to select which
      18             : // Spans from the input iterator are returned in the output.
      19             : //
      20             : // A note on Span lifetimes: as the FilterFunc reuses a Span with a mutable
      21             : // slice of Keys to reduce allocations, Spans returned by this iterator are only
      22             : // valid until the next relative or absolute positioning method is called.
      23             : type filteringIter struct {
      24             :         iter     FragmentIterator
      25             :         filterFn FilterFunc
      26             :         cmp      base.Compare
      27             : 
      28             :         // span is a mutable Span passed to the filterFn. The filterFn is free to
      29             :         // mutate this Span. The slice of Keys in the Span is reused with every call
      30             :         // to the filterFn.
      31             :         span Span
      32             : }
      33             : 
      34             : var _ FragmentIterator = (*filteringIter)(nil)
      35             : 
      36             : // Filter returns a new filteringIter that will filter the Spans from the
      37             : // provided child iterator using the provided FilterFunc.
      38           1 : func Filter(iter FragmentIterator, filter FilterFunc, cmp base.Compare) FragmentIterator {
      39           1 :         return MaybeAssert(&filteringIter{iter: iter, filterFn: filter, cmp: cmp}, cmp)
      40           1 : }
      41             : 
      42             : // SeekGE implements FragmentIterator.
      43           1 : func (i *filteringIter) SeekGE(key []byte) (*Span, error) {
      44           1 :         s, err := i.iter.SeekGE(key)
      45           1 :         if err != nil {
      46           0 :                 return nil, err
      47           0 :         }
      48           1 :         s, err = i.filter(s, +1)
      49           1 :         if err != nil {
      50           0 :                 return nil, err
      51           0 :         }
      52             :         // i.filter could return a span that's less than key, _if_ the filterFunc
      53             :         // (which has no knowledge of the seek key) mutated the span to end at a key
      54             :         // less than or equal to `key`. Detect this case and next/invalidate the iter.
      55           1 :         if s != nil && i.cmp(s.End, key) <= 0 {
      56           1 :                 return i.Next()
      57           1 :         }
      58           1 :         return s, nil
      59             : }
      60             : 
      61             : // SeekLT implements FragmentIterator.
      62           1 : func (i *filteringIter) SeekLT(key []byte) (*Span, error) {
      63           1 :         span, err := i.iter.SeekLT(key)
      64           1 :         if err != nil {
      65           0 :                 return nil, err
      66           0 :         }
      67           1 :         span, err = i.filter(span, -1)
      68           1 :         if err != nil {
      69           0 :                 return nil, err
      70           0 :         }
      71             :         // i.filter could return a span that's >= key, _if_ the filterFunc (which has
      72             :         // no knowledge of the seek key) mutated the span to start at a key greater
      73             :         // than or equal to `key`. Detect this case and prev/invalidate the iter.
      74           1 :         if span != nil && i.cmp(span.Start, key) >= 0 {
      75           1 :                 return i.Prev()
      76           1 :         }
      77           1 :         return span, nil
      78             : }
      79             : 
      80             : // First implements FragmentIterator.
      81           1 : func (i *filteringIter) First() (*Span, error) {
      82           1 :         s, err := i.iter.First()
      83           1 :         if err != nil {
      84           0 :                 return nil, err
      85           0 :         }
      86           1 :         return i.filter(s, +1)
      87             : }
      88             : 
      89             : // Last implements FragmentIterator.
      90           1 : func (i *filteringIter) Last() (*Span, error) {
      91           1 :         s, err := i.iter.Last()
      92           1 :         if err != nil {
      93           0 :                 return nil, err
      94           0 :         }
      95           1 :         return i.filter(s, -1)
      96             : }
      97             : 
      98             : // Next implements FragmentIterator.
      99           1 : func (i *filteringIter) Next() (*Span, error) {
     100           1 :         s, err := i.iter.Next()
     101           1 :         if err != nil {
     102           0 :                 return nil, err
     103           0 :         }
     104           1 :         return i.filter(s, +1)
     105             : }
     106             : 
     107             : // Prev implements FragmentIterator.
     108           1 : func (i *filteringIter) Prev() (*Span, error) {
     109           1 :         s, err := i.iter.Prev()
     110           1 :         if err != nil {
     111           0 :                 return nil, err
     112           0 :         }
     113           1 :         return i.filter(s, -1)
     114             : }
     115             : 
     116             : // Close implements FragmentIterator.
     117           1 : func (i *filteringIter) Close() error {
     118           1 :         return i.iter.Close()
     119           1 : }
     120             : 
     121             : // filter uses the filterFn (if configured) to filter and possibly mutate the
     122             : // given Span. If the current Span is to be skipped, the iterator continues
     123             : // iterating in the given direction until it lands on a Span that should be
     124             : // returned, or the iterator becomes invalid.
     125           1 : func (i *filteringIter) filter(span *Span, dir int8) (*Span, error) {
     126           1 :         if i.filterFn == nil {
     127           0 :                 return span, nil
     128           0 :         }
     129           1 :         var err error
     130           1 :         for span != nil {
     131           1 :                 if keep := i.filterFn(span, &i.span); keep {
     132           1 :                         return &i.span, nil
     133           1 :                 }
     134           1 :                 if dir == +1 {
     135           1 :                         span, err = i.iter.Next()
     136           1 :                 } else {
     137           1 :                         span, err = i.iter.Prev()
     138           1 :                 }
     139             :         }
     140             :         // NB: err may be nil or non-nil.
     141           1 :         return span, err
     142             : }
     143             : 
     144             : // WrapChildren implements FragmentIterator.
     145           0 : func (i *filteringIter) WrapChildren(wrap WrapFn) {
     146           0 :         i.iter = wrap(i.iter)
     147           0 : }

Generated by: LCOV version 1.14