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

Generated by: LCOV version 1.14