LCOV - code coverage report
Current view: top level - pebble/internal/itertest - probe.go (source / functions) Hit Total Coverage
Test: 2024-06-18 08:15Z 3b3f10c0 - tests only.lcov Lines: 95 109 87.2 %
Date: 2024-06-18 08:16:20 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             :                 KV  *base.InternalKV
      70             :                 Err error
      71             :         }
      72             : }
      73             : 
      74             : // Probe defines an interface for probes that may inspect or mutate internal
      75             : // iterator behavior.
      76             : type Probe interface {
      77             :         // Probe inspects, and possibly manipulates, iterator operations' results.
      78             :         Probe(*ProbeContext)
      79             : }
      80             : 
      81             : // ProbeContext provides the context within which a Probe is run. It includes
      82             : // information about the iterator operation in progress.
      83             : type ProbeContext struct {
      84             :         Op
      85             :         ProbeState
      86             : }
      87             : 
      88             : // ProbeState holds state additional to the context of the operation that's
      89             : // accessible to probes.
      90             : type ProbeState struct {
      91             :         *base.Comparer
      92             :         Log io.Writer
      93             : }
      94             : 
      95             : // Attach takes an iterator, an initial state and a probe, returning an iterator
      96             : // that will invoke the provided Probe on all internal iterator operations.
      97             : func Attach(
      98             :         iter base.InternalIterator, initialState ProbeState, probes ...Probe,
      99           1 : ) base.InternalIterator {
     100           1 :         for i := range probes {
     101           1 :                 iter = &probeIterator{
     102           1 :                         iter:  iter,
     103           1 :                         probe: probes[i],
     104           1 :                         probeCtx: ProbeContext{
     105           1 :                                 ProbeState: initialState,
     106           1 :                         },
     107           1 :                 }
     108           1 :         }
     109           1 :         return iter
     110             : }
     111             : 
     112             : // MustParseProbes parses each DSL string as a separate probe, returning a slice
     113             : // of parsed probes. Panics if any of the probes fail to parse.
     114           1 : func MustParseProbes(parser *dsl.Parser[Probe], probeDSLs ...string) []Probe {
     115           1 :         probes := make([]Probe, len(probeDSLs))
     116           1 :         var err error
     117           1 :         for i := range probeDSLs {
     118           1 :                 probes[i], err = parser.Parse(probeDSLs[i])
     119           1 :                 if err != nil {
     120           0 :                         panic(err)
     121             :                 }
     122             :         }
     123           1 :         return probes
     124             : }
     125             : 
     126             : type probeIterator struct {
     127             :         iter     base.InternalIterator
     128             :         probe    Probe
     129             :         probeCtx ProbeContext
     130             : }
     131             : 
     132             : // Assert that errIterator implements the internal iterator interface.
     133             : var _ base.InternalIterator = (*probeIterator)(nil)
     134             : 
     135             : // handleOp takes an Op representing the iterator operation performed, and the
     136             : // underlying iterator's return value. It populates `Return.Err` and invokes the
     137             : // probe.
     138           1 : func (p *probeIterator) handleOp(preProbeOp Op) *base.InternalKV {
     139           1 :         p.probeCtx.Op = preProbeOp
     140           1 :         if preProbeOp.Return.KV == nil && p.iter != nil {
     141           1 :                 p.probeCtx.Op.Return.Err = p.iter.Error()
     142           1 :         }
     143             : 
     144           1 :         p.probe.Probe(&p.probeCtx)
     145           1 :         return p.probeCtx.Op.Return.KV
     146             : }
     147             : 
     148           1 : func (p *probeIterator) SeekGE(key []byte, flags base.SeekGEFlags) *base.InternalKV {
     149           1 :         op := Op{
     150           1 :                 Kind:    OpSeekGE,
     151           1 :                 SeekKey: key,
     152           1 :         }
     153           1 :         if p.iter != nil {
     154           1 :                 op.Return.KV = p.iter.SeekGE(key, flags)
     155           1 :         }
     156           1 :         return p.handleOp(op)
     157             : }
     158             : 
     159           1 : func (p *probeIterator) SeekPrefixGE(prefix, key []byte, flags base.SeekGEFlags) *base.InternalKV {
     160           1 :         op := Op{
     161           1 :                 Kind:    OpSeekPrefixGE,
     162           1 :                 SeekKey: key,
     163           1 :         }
     164           1 :         if p.iter != nil {
     165           1 :                 op.Return.KV = p.iter.SeekPrefixGE(prefix, key, flags)
     166           1 :         }
     167           1 :         return p.handleOp(op)
     168             : }
     169             : 
     170           1 : func (p *probeIterator) SeekLT(key []byte, flags base.SeekLTFlags) *base.InternalKV {
     171           1 :         op := Op{
     172           1 :                 Kind:    OpSeekLT,
     173           1 :                 SeekKey: key,
     174           1 :         }
     175           1 :         if p.iter != nil {
     176           1 :                 op.Return.KV = p.iter.SeekLT(key, flags)
     177           1 :         }
     178           1 :         return p.handleOp(op)
     179             : }
     180             : 
     181           1 : func (p *probeIterator) First() *base.InternalKV {
     182           1 :         op := Op{Kind: OpFirst}
     183           1 :         if p.iter != nil {
     184           1 :                 op.Return.KV = p.iter.First()
     185           1 :         }
     186           1 :         return p.handleOp(op)
     187             : }
     188             : 
     189           1 : func (p *probeIterator) Last() *base.InternalKV {
     190           1 :         op := Op{Kind: OpLast}
     191           1 :         if p.iter != nil {
     192           1 :                 op.Return.KV = p.iter.Last()
     193           1 :         }
     194           1 :         return p.handleOp(op)
     195             : }
     196             : 
     197           1 : func (p *probeIterator) Next() *base.InternalKV {
     198           1 :         op := Op{Kind: OpNext}
     199           1 :         if p.iter != nil {
     200           1 :                 op.Return.KV = p.iter.Next()
     201           1 :         }
     202           1 :         return p.handleOp(op)
     203             : }
     204             : 
     205           1 : func (p *probeIterator) NextPrefix(succKey []byte) *base.InternalKV {
     206           1 :         op := Op{Kind: OpNextPrefix, SeekKey: succKey}
     207           1 :         if p.iter != nil {
     208           1 :                 op.Return.KV = p.iter.NextPrefix(succKey)
     209           1 :         }
     210           1 :         return p.handleOp(op)
     211             : }
     212             : 
     213           1 : func (p *probeIterator) Prev() *base.InternalKV {
     214           1 :         op := Op{Kind: OpPrev}
     215           1 :         if p.iter != nil {
     216           1 :                 op.Return.KV = p.iter.Prev()
     217           1 :         }
     218           1 :         return p.handleOp(op)
     219             : }
     220             : 
     221           1 : func (p *probeIterator) Error() error {
     222           1 :         return p.probeCtx.Op.Return.Err
     223           1 : }
     224             : 
     225           1 : func (p *probeIterator) Close() error {
     226           1 :         op := Op{Kind: OpClose}
     227           1 :         if p.iter != nil {
     228           1 :                 op.Return.Err = p.iter.Close()
     229           1 :         }
     230             : 
     231             :         // NB: Can't use handleOp because a close returns its error value directly
     232             :         // (and does not return a KV pair). We don't want to call iter.Error()
     233             :         // again, but rather use the error directly returned by iter.Close().
     234           1 :         p.probeCtx.Op = op
     235           1 :         p.probe.Probe(&p.probeCtx)
     236           1 :         return p.Error()
     237             : }
     238             : 
     239           0 : func (p *probeIterator) SetBounds(lower, upper []byte) {
     240           0 :         if p.iter != nil {
     241           0 :                 p.iter.SetBounds(lower, upper)
     242           0 :         }
     243             : }
     244             : 
     245           0 : func (p *probeIterator) SetContext(ctx context.Context) {
     246           0 :         if p.iter != nil {
     247           0 :                 p.iter.SetContext(ctx)
     248           0 :         }
     249             : }
     250             : 
     251           0 : func (p *probeIterator) String() string {
     252           0 :         if p.iter != nil {
     253           0 :                 return fmt.Sprintf("probeIterator(%q)", p.iter.String())
     254           0 :         }
     255           0 :         return "probeIterator(nil)"
     256             : }

Generated by: LCOV version 1.14