github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/tool/util.go (about)

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