LCOV - code coverage report
Current view: top level - pebble/internal/keyspan - logging_iter.go (source / functions) Hit Total Coverage
Test: 2024-04-26 08:15Z 282f0c3b - tests + meta.lcov Lines: 85 91 93.4 %
Date: 2024-04-26 08:16:38 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 keyspan
       6             : 
       7             : import (
       8             :         "fmt"
       9             : 
      10             :         "github.com/cockroachdb/pebble/internal/base"
      11             :         "github.com/cockroachdb/pebble/internal/treeprinter"
      12             : )
      13             : 
      14             : // WrapFn is the prototype for a function that wraps a FragmentIterator.
      15             : type WrapFn func(in FragmentIterator) FragmentIterator
      16             : 
      17             : // InjectLogging wraps all iterators in a stack with logging iterators,
      18             : // producing log messages showing each operation and its result.
      19           1 : func InjectLogging(iter FragmentIterator, logger base.Logger) FragmentIterator {
      20           1 :         // All iterators in the stack will use the same logging state.
      21           1 :         state := &loggingState{
      22           1 :                 log: logger,
      23           1 :         }
      24           1 :         var wrap WrapFn
      25           1 :         wrap = func(in FragmentIterator) FragmentIterator {
      26           1 :                 if in == nil {
      27           0 :                         return nil
      28           0 :                 }
      29             :                 // Recursively wrap all descendants.
      30           1 :                 in.WrapChildren(wrap)
      31           1 :                 return newLoggingIter(state, in)
      32             :         }
      33           1 :         return wrap(iter)
      34             : }
      35             : 
      36           1 : func newLoggingIter(state *loggingState, iter FragmentIterator) FragmentIterator {
      37           1 :         return &loggingIter{
      38           1 :                 iter:    iter,
      39           1 :                 state:   state,
      40           1 :                 context: fmt.Sprintf("%T(%p):", iter, iter),
      41           1 :         }
      42           1 : }
      43             : 
      44             : // loggingIter is a pass-through FragmentIterator wrapper which performs checks
      45             : // on what the wrapped iterator returns.
      46             : type loggingIter struct {
      47             :         iter    FragmentIterator
      48             :         state   *loggingState
      49             :         context string
      50             : }
      51             : 
      52             : // loggingState is shared by all iterators in a stack.
      53             : type loggingState struct {
      54             :         node treeprinter.Node
      55             :         log  base.Logger
      56             : }
      57             : 
      58           1 : func (i *loggingIter) opStartf(format string, args ...any) func(results ...any) {
      59           1 :         savedNode := i.state.node
      60           1 : 
      61           1 :         n := i.state.node
      62           1 :         topLevelOp := false
      63           1 :         if n == (treeprinter.Node{}) {
      64           1 :                 n = treeprinter.New()
      65           1 :                 topLevelOp = true
      66           1 :         }
      67           1 :         op := fmt.Sprintf(format, args...)
      68           1 : 
      69           1 :         child := n.Childf("%s %s", i.context, op)
      70           1 :         i.state.node = child
      71           1 : 
      72           1 :         return func(results ...any) {
      73           1 :                 if len(results) > 0 {
      74           1 :                         child.Childf("%s", fmt.Sprint(results...))
      75           1 :                 }
      76           1 :                 if topLevelOp {
      77           1 :                         for _, row := range n.FormattedRows() {
      78           1 :                                 i.state.log.Infof("%s\n", row)
      79           1 :                         }
      80             :                 }
      81           1 :                 i.state.node = savedNode
      82             :         }
      83             : }
      84             : 
      85             : var _ FragmentIterator = (*loggingIter)(nil)
      86             : 
      87             : // SeekGE implements FragmentIterator.
      88           1 : func (i *loggingIter) SeekGE(key []byte) (*Span, error) {
      89           1 :         opEnd := i.opStartf("SeekGE(%q)", key)
      90           1 :         span, err := i.iter.SeekGE(key)
      91           1 :         opEnd(span, err)
      92           1 :         return span, err
      93           1 : }
      94             : 
      95             : // SeekLT implements FragmentIterator.
      96           1 : func (i *loggingIter) SeekLT(key []byte) (*Span, error) {
      97           1 :         opEnd := i.opStartf("SeekLT(%q)", key)
      98           1 :         span, err := i.iter.SeekLT(key)
      99           1 :         opEnd(span, err)
     100           1 :         return span, err
     101           1 : }
     102             : 
     103             : // First implements FragmentIterator.
     104           1 : func (i *loggingIter) First() (*Span, error) {
     105           1 :         opEnd := i.opStartf("First()")
     106           1 :         span, err := i.iter.First()
     107           1 :         opEnd(span, err)
     108           1 :         return span, err
     109           1 : }
     110             : 
     111             : // Last implements FragmentIterator.
     112           1 : func (i *loggingIter) Last() (*Span, error) {
     113           1 :         opEnd := i.opStartf("Last()")
     114           1 :         span, err := i.iter.Last()
     115           1 :         opEnd(span, err)
     116           1 :         return span, err
     117           1 : }
     118             : 
     119             : // Next implements FragmentIterator.
     120           1 : func (i *loggingIter) Next() (*Span, error) {
     121           1 :         opEnd := i.opStartf("Next()")
     122           1 :         span, err := i.iter.Next()
     123           1 :         opEnd(span, err)
     124           1 :         return span, err
     125           1 : }
     126             : 
     127             : // Prev implements FragmentIterator.
     128           1 : func (i *loggingIter) Prev() (*Span, error) {
     129           1 :         opEnd := i.opStartf("Prev()")
     130           1 :         span, err := i.iter.Prev()
     131           1 :         opEnd(span, err)
     132           1 :         return span, err
     133           1 : }
     134             : 
     135             : // Close implements FragmentIterator.
     136           1 : func (i *loggingIter) Close() error {
     137           1 :         opEnd := i.opStartf("Close()")
     138           1 :         err := i.iter.Close()
     139           1 :         if err != nil {
     140           0 :                 opEnd(err)
     141           1 :         } else {
     142           1 :                 opEnd()
     143           1 :         }
     144           1 :         return err
     145             : }
     146             : 
     147             : // WrapChildren implements FragmentIterator.
     148           0 : func (i *loggingIter) WrapChildren(wrap WrapFn) {
     149           0 :         i.iter = wrap(i.iter)
     150           0 : }

Generated by: LCOV version 1.14