LCOV - code coverage report
Current view: top level - pebble/internal/itertest - probe.go (source / functions) Hit Total Coverage
Test: 2024-04-01 08:16Z 1c7bcd1c - tests only.lcov Lines: 95 109 87.2 %
Date: 2024-04-01 08:17:26 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2023 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 itertest
       6             : 
       7             : import (
       8             :         "context"
       9             :         "fmt"
      10             :         "io"
      11             : 
      12             :         "github.com/cockroachdb/pebble/internal/base"
      13             :         "github.com/cockroachdb/pebble/internal/dsl"
      14             : )
      15             : 
      16             : // OpKind indicates the type of iterator operation being performed.
      17             : type OpKind int8
      18             : 
      19             : const (
      20             :         // OpSeekGE indicates a SeekGE internal iterator operation.
      21             :         OpSeekGE OpKind = iota
      22             :         // OpSeekPrefixGE indicates a SeekPrefixGE internal iterator operation.
      23             :         OpSeekPrefixGE
      24             :         // OpSeekLT indicates a SeekLT internal iterator operation.
      25             :         OpSeekLT
      26             :         // OpFirst indicates a First internal iterator operation.
      27             :         OpFirst
      28             :         // OpLast indicates a Last internal iterator operation.
      29             :         OpLast
      30             :         // OpNext indicates a Next internal iterator operation.
      31             :         OpNext
      32             :         // OpNextPrefix indicates a NextPrefix internal iterator operation.
      33             :         OpNextPrefix
      34             :         // OpPrev indicates a Prev internal iterator operation.
      35             :         OpPrev
      36             :         // OpClose indicates a Close internal iterator operation.
      37             :         OpClose
      38             :         numOpKinds
      39             : )
      40             : 
      41             : var opNames = [numOpKinds]string{
      42             :         OpSeekGE:       "OpSeekGE",
      43             :         OpSeekPrefixGE: "OpSeekPrefixGE",
      44             :         OpSeekLT:       "OpSeekLT",
      45             :         OpFirst:        "OpFirst",
      46             :         OpLast:         "OpLast",
      47             :         OpNext:         "OpNext",
      48             :         OpNextPrefix:   "OpNextPrefix",
      49             :         OpPrev:         "OpPrev",
      50             :         OpClose:        "OpClose",
      51             : }
      52             : 
      53             : // OpKind implements Predicate.
      54             : var _ Predicate = OpKind(0)
      55             : 
      56             : // String imlements fmt.Stringer.
      57           1 : func (o OpKind) String() string { return opNames[o] }
      58             : 
      59             : // Evaluate implements Predicate.
      60           1 : func (o OpKind) Evaluate(pctx *ProbeContext) bool { return pctx.Op.Kind == o }
      61             : 
      62             : // Op describes an individual iterator operation being performed.
      63             : type Op struct {
      64             :         Kind    OpKind
      65             :         SeekKey []byte
      66             :         // Return is initialized with the return result of the underlying iterator.
      67             :         // Probes may mutate them.
      68             :         Return struct {
      69             :                 Key   *base.InternalKey
      70             :                 Value base.LazyValue
      71             :                 Err   error
      72             :         }
      73             : }
      74             : 
      75             : // Probe defines an interface for probes that may inspect or mutate internal
      76             : // iterator behavior.
      77             : type Probe interface {
      78             :         // Probe inspects, and possibly manipulates, iterator operations' results.
      79             :         Probe(*ProbeContext)
      80             : }
      81             : 
      82             : // ProbeContext provides the context within which a Probe is run. It includes
      83             : // information about the iterator operation in progress.
      84             : type ProbeContext struct {
      85             :         Op
      86             :         ProbeState
      87             : }
      88             : 
      89             : // ProbeState holds state additional to the context of the operation that's
      90             : // accessible to probes.
      91             : type ProbeState struct {
      92             :         *base.Comparer
      93             :         Log io.Writer
      94             : }
      95             : 
      96             : // Attach takes an iterator, an initial state and a probe, returning an iterator
      97             : // that will invoke the provided Probe on all internal iterator operations.
      98             : func Attach(
      99             :         iter base.InternalIterator, initialState ProbeState, probes ...Probe,
     100           1 : ) base.InternalIterator {
     101           1 :         for i := range probes {
     102           1 :                 iter = &probeIterator{
     103           1 :                         iter:  iter,
     104           1 :                         probe: probes[i],
     105           1 :                         probeCtx: ProbeContext{
     106           1 :                                 ProbeState: initialState,
     107           1 :                         },
     108           1 :                 }
     109           1 :         }
     110           1 :         return iter
     111             : }
     112             : 
     113             : // MustParseProbes parses each DSL string as a separate probe, returning a slice
     114             : // of parsed probes. Panics if any of the probes fail to parse.
     115           1 : func MustParseProbes(parser *dsl.Parser[Probe], probeDSLs ...string) []Probe {
     116           1 :         probes := make([]Probe, len(probeDSLs))
     117           1 :         var err error
     118           1 :         for i := range probeDSLs {
     119           1 :                 probes[i], err = parser.Parse(probeDSLs[i])
     120           1 :                 if err != nil {
     121           0 :                         panic(err)
     122             :                 }
     123             :         }
     124           1 :         return probes
     125             : }
     126             : 
     127             : type probeIterator struct {
     128             :         iter     base.InternalIterator
     129             :         probe    Probe
     130             :         probeCtx ProbeContext
     131             : }
     132             : 
     133             : // Assert that errIterator implements the internal iterator interface.
     134             : var _ base.InternalIterator = (*probeIterator)(nil)
     135             : 
     136             : // handleOp takes an Op representing the iterator operation performed, and the
     137             : // underlying iterator's return value. It populates `Return.Err` and invokes the
     138             : // probe.
     139           1 : func (p *probeIterator) handleOp(preProbeOp Op) (*base.InternalKey, base.LazyValue) {
     140           1 :         p.probeCtx.Op = preProbeOp
     141           1 :         if preProbeOp.Return.Key == nil && p.iter != nil {
     142           1 :                 p.probeCtx.Op.Return.Err = p.iter.Error()
     143           1 :         }
     144             : 
     145           1 :         p.probe.Probe(&p.probeCtx)
     146           1 :         return p.probeCtx.Op.Return.Key, p.probeCtx.Op.Return.Value
     147             : }
     148             : 
     149             : func (p *probeIterator) SeekGE(
     150             :         key []byte, flags base.SeekGEFlags,
     151           1 : ) (*base.InternalKey, base.LazyValue) {
     152           1 :         op := Op{
     153           1 :                 Kind:    OpSeekGE,
     154           1 :                 SeekKey: key,
     155           1 :         }
     156           1 :         if p.iter != nil {
     157           1 :                 op.Return.Key, op.Return.Value = p.iter.SeekGE(key, flags)
     158           1 :         }
     159           1 :         return p.handleOp(op)
     160             : }
     161             : 
     162             : func (p *probeIterator) SeekPrefixGE(
     163             :         prefix, key []byte, flags base.SeekGEFlags,
     164           1 : ) (*base.InternalKey, base.LazyValue) {
     165           1 :         op := Op{
     166           1 :                 Kind:    OpSeekPrefixGE,
     167           1 :                 SeekKey: key,
     168           1 :         }
     169           1 :         if p.iter != nil {
     170           1 :                 op.Return.Key, op.Return.Value = p.iter.SeekPrefixGE(prefix, key, flags)
     171           1 :         }
     172           1 :         return p.handleOp(op)
     173             : }
     174             : 
     175             : func (p *probeIterator) SeekLT(
     176             :         key []byte, flags base.SeekLTFlags,
     177           1 : ) (*base.InternalKey, base.LazyValue) {
     178           1 :         op := Op{
     179           1 :                 Kind:    OpSeekLT,
     180           1 :                 SeekKey: key,
     181           1 :         }
     182           1 :         if p.iter != nil {
     183           1 :                 op.Return.Key, op.Return.Value = p.iter.SeekLT(key, flags)
     184           1 :         }
     185           1 :         return p.handleOp(op)
     186             : }
     187             : 
     188           1 : func (p *probeIterator) First() (*base.InternalKey, base.LazyValue) {
     189           1 :         op := Op{Kind: OpFirst}
     190           1 :         if p.iter != nil {
     191           1 :                 op.Return.Key, op.Return.Value = p.iter.First()
     192           1 :         }
     193           1 :         return p.handleOp(op)
     194             : }
     195             : 
     196           1 : func (p *probeIterator) Last() (*base.InternalKey, base.LazyValue) {
     197           1 :         op := Op{Kind: OpLast}
     198           1 :         if p.iter != nil {
     199           1 :                 op.Return.Key, op.Return.Value = p.iter.Last()
     200           1 :         }
     201           1 :         return p.handleOp(op)
     202             : }
     203             : 
     204           1 : func (p *probeIterator) Next() (*base.InternalKey, base.LazyValue) {
     205           1 :         op := Op{Kind: OpNext}
     206           1 :         if p.iter != nil {
     207           1 :                 op.Return.Key, op.Return.Value = p.iter.Next()
     208           1 :         }
     209           1 :         return p.handleOp(op)
     210             : }
     211             : 
     212           1 : func (p *probeIterator) NextPrefix(succKey []byte) (*base.InternalKey, base.LazyValue) {
     213           1 :         op := Op{Kind: OpNextPrefix, SeekKey: succKey}
     214           1 :         if p.iter != nil {
     215           1 :                 op.Return.Key, op.Return.Value = p.iter.NextPrefix(succKey)
     216           1 :         }
     217           1 :         return p.handleOp(op)
     218             : }
     219             : 
     220           1 : func (p *probeIterator) Prev() (*base.InternalKey, base.LazyValue) {
     221           1 :         op := Op{Kind: OpPrev}
     222           1 :         if p.iter != nil {
     223           1 :                 op.Return.Key, op.Return.Value = p.iter.Prev()
     224           1 :         }
     225           1 :         return p.handleOp(op)
     226             : }
     227             : 
     228           1 : func (p *probeIterator) Error() error {
     229           1 :         return p.probeCtx.Op.Return.Err
     230           1 : }
     231             : 
     232           1 : func (p *probeIterator) Close() error {
     233           1 :         op := Op{Kind: OpClose}
     234           1 :         if p.iter != nil {
     235           1 :                 op.Return.Err = p.iter.Close()
     236           1 :         }
     237             : 
     238             :         // NB: Can't use handleOp because a close returns its error value directly
     239             :         // (and does not return a KV pair). We don't want to call iter.Error()
     240             :         // again, but rather use the error directly returned by iter.Close().
     241           1 :         p.probeCtx.Op = op
     242           1 :         p.probe.Probe(&p.probeCtx)
     243           1 :         return p.Error()
     244             : }
     245             : 
     246           0 : func (p *probeIterator) SetBounds(lower, upper []byte) {
     247           0 :         if p.iter != nil {
     248           0 :                 p.iter.SetBounds(lower, upper)
     249           0 :         }
     250             : }
     251             : 
     252           0 : func (p *probeIterator) SetContext(ctx context.Context) {
     253           0 :         if p.iter != nil {
     254           0 :                 p.iter.SetContext(ctx)
     255           0 :         }
     256             : }
     257             : 
     258           0 : func (p *probeIterator) String() string {
     259           0 :         if p.iter != nil {
     260           0 :                 return fmt.Sprintf("probeIterator(%q)", p.iter.String())
     261           0 :         }
     262           0 :         return "probeIterator(nil)"
     263             : }

Generated by: LCOV version 1.14