LCOV - code coverage report
Current view: top level - pebble/tool - util.go (source / functions) Hit Total Coverage
Test: 2024-03-25 08:17Z 86b5f54c - tests only.lcov Lines: 183 216 84.7 %
Date: 2024-03-25 08:17:54 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2019 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 tool
       6             : 
       7             : import (
       8             :         "encoding/hex"
       9             :         "fmt"
      10             :         "io"
      11             :         "sort"
      12             :         "strings"
      13             :         "time"
      14             : 
      15             :         "github.com/cockroachdb/errors"
      16             :         "github.com/cockroachdb/pebble/internal/base"
      17             :         "github.com/cockroachdb/pebble/internal/keyspan"
      18             :         "github.com/cockroachdb/pebble/sstable"
      19             :         "github.com/cockroachdb/pebble/vfs"
      20             : )
      21             : 
      22             : var timeNow = time.Now
      23             : 
      24             : type key []byte
      25             : 
      26           1 : func (k *key) String() string {
      27           1 :         return string(*k)
      28           1 : }
      29             : 
      30           1 : func (k *key) Type() string {
      31           1 :         return "key"
      32           1 : }
      33             : 
      34           1 : func (k *key) Set(v string) error {
      35           1 :         switch {
      36           1 :         case strings.HasPrefix(v, "hex:"):
      37           1 :                 v = strings.TrimPrefix(v, "hex:")
      38           1 :                 b, err := hex.DecodeString(v)
      39           1 :                 if err != nil {
      40           0 :                         return err
      41           0 :                 }
      42           1 :                 *k = key(b)
      43             : 
      44           1 :         case strings.HasPrefix(v, "raw:"):
      45           1 :                 *k = key(strings.TrimPrefix(v, "raw:"))
      46             : 
      47           1 :         default:
      48           1 :                 *k = key(v)
      49             :         }
      50           1 :         return nil
      51             : }
      52             : 
      53             : type keyFormatter struct {
      54             :         spec      string
      55             :         fn        base.FormatKey
      56             :         setByUser bool
      57             :         comparer  string
      58             : }
      59             : 
      60           1 : func (f *keyFormatter) String() string {
      61           1 :         return f.spec
      62           1 : }
      63             : 
      64           1 : func (f *keyFormatter) Type() string {
      65           1 :         return "keyFormatter"
      66           1 : }
      67             : 
      68           1 : func (f *keyFormatter) Set(spec string) error {
      69           1 :         f.spec = spec
      70           1 :         f.setByUser = true
      71           1 :         switch spec {
      72           1 :         case "null":
      73           1 :                 f.fn = formatKeyNull
      74           1 :         case "quoted":
      75           1 :                 f.fn = formatKeyQuoted
      76           1 :         case "pretty":
      77           1 :                 // Using "pretty" defaults to base.FormatBytes (just like formatKeyQuoted),
      78           1 :                 // except with the ability of having the comparer-provided formatter
      79           1 :                 // overwrite f.fn if there is one specified. We determine whether to do
      80           1 :                 // that overwrite through setByUser.
      81           1 :                 f.fn = formatKeyQuoted
      82           1 :                 f.setByUser = false
      83           0 :         case "size":
      84           0 :                 f.fn = formatKeySize
      85           1 :         default:
      86           1 :                 if strings.HasPrefix(spec, "pretty:") {
      87           1 :                         // Usage: pretty:<comparer-name>
      88           1 :                         f.comparer = spec[7:]
      89           1 :                         f.fn = formatKeyQuoted
      90           1 :                         return nil
      91           1 :                 }
      92           1 :                 if strings.Count(spec, "%") != 1 {
      93           0 :                         return errors.Errorf("unknown formatter: %q", errors.Safe(spec))
      94           0 :                 }
      95           1 :                 f.fn = func(v []byte) fmt.Formatter {
      96           1 :                         return fmtFormatter{f.spec, v}
      97           1 :                 }
      98             :         }
      99           1 :         return nil
     100             : }
     101             : 
     102           1 : func (f *keyFormatter) mustSet(spec string) {
     103           1 :         if err := f.Set(spec); err != nil {
     104           0 :                 panic(err)
     105             :         }
     106           1 :         f.setByUser = false
     107             : }
     108             : 
     109             : // Sets the appropriate formatter function for this comparer.
     110           1 : func (f *keyFormatter) setForComparer(comparerName string, comparers sstable.Comparers) {
     111           1 :         if f.setByUser && len(f.comparer) == 0 {
     112           1 :                 // User specified a different formatter, no-op.
     113           1 :                 return
     114           1 :         }
     115             : 
     116           1 :         if len(f.comparer) > 0 {
     117           1 :                 // User specified a comparer to reference for formatting, which takes
     118           1 :                 // precedence.
     119           1 :                 comparerName = f.comparer
     120           1 :         } else if len(comparerName) == 0 {
     121           0 :                 return
     122           0 :         }
     123             : 
     124           1 :         if cmp := comparers[comparerName]; cmp != nil && cmp.FormatKey != nil {
     125           1 :                 f.fn = cmp.FormatKey
     126           1 :         }
     127             : }
     128             : 
     129             : type valueFormatter struct {
     130             :         spec      string
     131             :         fn        base.FormatValue
     132             :         setByUser bool
     133             :         comparer  string
     134             : }
     135             : 
     136           1 : func (f *valueFormatter) String() string {
     137           1 :         return f.spec
     138           1 : }
     139             : 
     140           1 : func (f *valueFormatter) Type() string {
     141           1 :         return "valueFormatter"
     142           1 : }
     143             : 
     144           1 : func (f *valueFormatter) Set(spec string) error {
     145           1 :         f.spec = spec
     146           1 :         f.setByUser = true
     147           1 :         switch spec {
     148           1 :         case "null":
     149           1 :                 f.fn = formatValueNull
     150           1 :         case "quoted":
     151           1 :                 f.fn = formatValueQuoted
     152           1 :         case "pretty":
     153           1 :                 // Using "pretty" defaults to base.FormatBytes (just like
     154           1 :                 // formatValueQuoted), except with the ability of having the
     155           1 :                 // comparer-provided formatter overwrite f.fn if there is one specified. We
     156           1 :                 // determine whether to do that overwrite through setByUser.
     157           1 :                 f.fn = formatValueQuoted
     158           1 :                 f.setByUser = false
     159           1 :         case "size":
     160           1 :                 f.fn = formatValueSize
     161           1 :         default:
     162           1 :                 if strings.HasPrefix(spec, "pretty:") {
     163           1 :                         // Usage: pretty:<comparer-name>
     164           1 :                         f.comparer = spec[7:]
     165           1 :                         f.fn = formatValueQuoted
     166           1 :                         return nil
     167           1 :                 }
     168           1 :                 if strings.Count(spec, "%") != 1 {
     169           0 :                         return errors.Errorf("unknown formatter: %q", errors.Safe(spec))
     170           0 :                 }
     171           1 :                 f.fn = func(k, v []byte) fmt.Formatter {
     172           1 :                         return fmtFormatter{f.spec, v}
     173           1 :                 }
     174             :         }
     175           1 :         return nil
     176             : }
     177             : 
     178           1 : func (f *valueFormatter) mustSet(spec string) {
     179           1 :         if err := f.Set(spec); err != nil {
     180           0 :                 panic(err)
     181             :         }
     182           1 :         f.setByUser = false
     183             : }
     184             : 
     185             : // Sets the appropriate formatter function for this comparer.
     186           1 : func (f *valueFormatter) setForComparer(comparerName string, comparers sstable.Comparers) {
     187           1 :         if f.setByUser && len(f.comparer) == 0 {
     188           1 :                 // User specified a different formatter, no-op.
     189           1 :                 return
     190           1 :         }
     191             : 
     192           1 :         if len(f.comparer) > 0 {
     193           1 :                 // User specified a comparer to reference for formatting, which takes
     194           1 :                 // precedence.
     195           1 :                 comparerName = f.comparer
     196           1 :         } else if len(comparerName) == 0 {
     197           0 :                 return
     198           0 :         }
     199             : 
     200           1 :         if cmp := comparers[comparerName]; cmp != nil && cmp.FormatValue != nil {
     201           1 :                 f.fn = cmp.FormatValue
     202           1 :         }
     203             : }
     204             : 
     205             : type fmtFormatter struct {
     206             :         fmt string
     207             :         v   []byte
     208             : }
     209             : 
     210           1 : func (f fmtFormatter) Format(s fmt.State, c rune) {
     211           1 :         fmt.Fprintf(s, f.fmt, f.v)
     212           1 : }
     213             : 
     214             : type nullFormatter struct{}
     215             : 
     216           0 : func (nullFormatter) Format(s fmt.State, c rune) {
     217           0 : }
     218             : 
     219           0 : func formatKeyNull(v []byte) fmt.Formatter {
     220           0 :         return nullFormatter{}
     221           0 : }
     222             : 
     223           0 : func formatValueNull(k, v []byte) fmt.Formatter {
     224           0 :         return nullFormatter{}
     225           0 : }
     226             : 
     227           0 : func formatKeyQuoted(v []byte) fmt.Formatter {
     228           0 :         return base.FormatBytes(v)
     229           0 : }
     230             : 
     231           1 : func formatValueQuoted(k, v []byte) fmt.Formatter {
     232           1 :         return base.FormatBytes(v)
     233           1 : }
     234             : 
     235             : type sizeFormatter []byte
     236             : 
     237           1 : func (v sizeFormatter) Format(s fmt.State, c rune) {
     238           1 :         fmt.Fprintf(s, "<%d>", len(v))
     239           1 : }
     240             : 
     241           0 : func formatKeySize(v []byte) fmt.Formatter {
     242           0 :         return sizeFormatter(v)
     243           0 : }
     244             : 
     245           1 : func formatValueSize(k, v []byte) fmt.Formatter {
     246           1 :         return sizeFormatter(v)
     247           1 : }
     248             : 
     249           1 : func formatKey(w io.Writer, fmtKey keyFormatter, key *base.InternalKey) bool {
     250           1 :         if fmtKey.spec == "null" {
     251           1 :                 return false
     252           1 :         }
     253           1 :         fmt.Fprintf(w, "%s", key.Pretty(fmtKey.fn))
     254           1 :         return true
     255             : }
     256             : 
     257           1 : func formatSeqNumRange(w io.Writer, start, end uint64) {
     258           1 :         fmt.Fprintf(w, "<#%d-#%d>", start, end)
     259           1 : }
     260             : 
     261           1 : func formatKeyRange(w io.Writer, fmtKey keyFormatter, start, end *base.InternalKey) {
     262           1 :         if fmtKey.spec == "null" {
     263           1 :                 return
     264           1 :         }
     265           1 :         fmt.Fprintf(w, "[%s-%s]", start.Pretty(fmtKey.fn), end.Pretty(fmtKey.fn))
     266             : }
     267             : 
     268             : func formatKeyValue(
     269             :         w io.Writer, fmtKey keyFormatter, fmtValue valueFormatter, key *base.InternalKey, value []byte,
     270           1 : ) {
     271           1 :         if key.Kind() == base.InternalKeyKindRangeDelete {
     272           1 :                 if fmtKey.spec != "null" {
     273           1 :                         fmt.Fprintf(w, "%s-%s#%d,%s",
     274           1 :                                 fmtKey.fn(key.UserKey), fmtKey.fn(value),
     275           1 :                                 key.SeqNum(), key.Kind())
     276           1 :                 }
     277           1 :         } else {
     278           1 :                 needDelimiter := formatKey(w, fmtKey, key)
     279           1 :                 if fmtValue.spec != "null" {
     280           1 :                         if needDelimiter {
     281           1 :                                 w.Write([]byte{' '})
     282           1 :                         }
     283           1 :                         fmt.Fprintf(w, "%s", fmtValue.fn(key.UserKey, value))
     284             :                 }
     285             :         }
     286           1 :         w.Write([]byte{'\n'})
     287             : }
     288             : 
     289           1 : func formatSpan(w io.Writer, fmtKey keyFormatter, fmtValue valueFormatter, s *keyspan.Span) {
     290           1 :         if fmtKey.spec != "null" {
     291           1 :                 fmt.Fprintf(w, "[%s-%s):\n", fmtKey.fn(s.Start), fmtKey.fn(s.End))
     292           1 :                 for _, k := range s.Keys {
     293           1 :                         fmt.Fprintf(w, "  #%d,%s", k.SeqNum(), k.Kind())
     294           1 :                         switch k.Kind() {
     295           1 :                         case base.InternalKeyKindRangeKeySet:
     296           1 :                                 fmt.Fprintf(w, ": %s %s", k.Suffix, fmtValue.fn(s.Start, k.Value))
     297           1 :                         case base.InternalKeyKindRangeKeyUnset:
     298           1 :                                 fmt.Fprintf(w, ": %s", k.Suffix)
     299             :                         }
     300           1 :                         w.Write([]byte{'\n'})
     301             :                 }
     302             :         }
     303             : }
     304             : 
     305           1 : func walk(stderr io.Writer, fs vfs.FS, dir string, fn func(path string)) {
     306           1 :         paths, err := fs.List(dir)
     307           1 :         if err != nil {
     308           0 :                 fmt.Fprintf(stderr, "%s: %v\n", dir, err)
     309           0 :                 return
     310           0 :         }
     311           1 :         sort.Strings(paths)
     312           1 :         for _, part := range paths {
     313           1 :                 path := fs.PathJoin(dir, part)
     314           1 :                 info, err := fs.Stat(path)
     315           1 :                 if err != nil {
     316           0 :                         fmt.Fprintf(stderr, "%s: %v\n", path, err)
     317           0 :                         continue
     318             :                 }
     319           1 :                 if info.IsDir() {
     320           1 :                         walk(stderr, fs, path, fn)
     321           1 :                 } else {
     322           1 :                         fn(path)
     323           1 :                 }
     324             :         }
     325             : }

Generated by: LCOV version 1.14