mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 17:15:18 +00:00
326 lines
7.2 KiB
Go
326 lines
7.2 KiB
Go
// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
|
// of this source code is governed by a BSD-style license that can be found in
|
|
// the LICENSE file.
|
|
|
|
package tool
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
"github.com/cockroachdb/pebble/internal/base"
|
|
"github.com/cockroachdb/pebble/internal/keyspan"
|
|
"github.com/cockroachdb/pebble/sstable"
|
|
"github.com/cockroachdb/pebble/vfs"
|
|
)
|
|
|
|
var timeNow = time.Now
|
|
|
|
type key []byte
|
|
|
|
func (k *key) String() string {
|
|
return string(*k)
|
|
}
|
|
|
|
func (k *key) Type() string {
|
|
return "key"
|
|
}
|
|
|
|
func (k *key) Set(v string) error {
|
|
switch {
|
|
case strings.HasPrefix(v, "hex:"):
|
|
v = strings.TrimPrefix(v, "hex:")
|
|
b, err := hex.DecodeString(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*k = key(b)
|
|
|
|
case strings.HasPrefix(v, "raw:"):
|
|
*k = key(strings.TrimPrefix(v, "raw:"))
|
|
|
|
default:
|
|
*k = key(v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type keyFormatter struct {
|
|
spec string
|
|
fn base.FormatKey
|
|
setByUser bool
|
|
comparer string
|
|
}
|
|
|
|
func (f *keyFormatter) String() string {
|
|
return f.spec
|
|
}
|
|
|
|
func (f *keyFormatter) Type() string {
|
|
return "keyFormatter"
|
|
}
|
|
|
|
func (f *keyFormatter) Set(spec string) error {
|
|
f.spec = spec
|
|
f.setByUser = true
|
|
switch spec {
|
|
case "null":
|
|
f.fn = formatKeyNull
|
|
case "quoted":
|
|
f.fn = formatKeyQuoted
|
|
case "pretty":
|
|
// Using "pretty" defaults to base.FormatBytes (just like formatKeyQuoted),
|
|
// except with the ability of having the comparer-provided formatter
|
|
// overwrite f.fn if there is one specified. We determine whether to do
|
|
// that overwrite through setByUser.
|
|
f.fn = formatKeyQuoted
|
|
f.setByUser = false
|
|
case "size":
|
|
f.fn = formatKeySize
|
|
default:
|
|
if strings.HasPrefix(spec, "pretty:") {
|
|
// Usage: pretty:<comparer-name>
|
|
f.comparer = spec[7:]
|
|
f.fn = formatKeyQuoted
|
|
return nil
|
|
}
|
|
if strings.Count(spec, "%") != 1 {
|
|
return errors.Errorf("unknown formatter: %q", errors.Safe(spec))
|
|
}
|
|
f.fn = func(v []byte) fmt.Formatter {
|
|
return fmtFormatter{f.spec, v}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *keyFormatter) mustSet(spec string) {
|
|
if err := f.Set(spec); err != nil {
|
|
panic(err)
|
|
}
|
|
f.setByUser = false
|
|
}
|
|
|
|
// Sets the appropriate formatter function for this comparer.
|
|
func (f *keyFormatter) setForComparer(comparerName string, comparers sstable.Comparers) {
|
|
if f.setByUser && len(f.comparer) == 0 {
|
|
// User specified a different formatter, no-op.
|
|
return
|
|
}
|
|
|
|
if len(f.comparer) > 0 {
|
|
// User specified a comparer to reference for formatting, which takes
|
|
// precedence.
|
|
comparerName = f.comparer
|
|
} else if len(comparerName) == 0 {
|
|
return
|
|
}
|
|
|
|
if cmp := comparers[comparerName]; cmp != nil && cmp.FormatKey != nil {
|
|
f.fn = cmp.FormatKey
|
|
}
|
|
}
|
|
|
|
type valueFormatter struct {
|
|
spec string
|
|
fn base.FormatValue
|
|
setByUser bool
|
|
comparer string
|
|
}
|
|
|
|
func (f *valueFormatter) String() string {
|
|
return f.spec
|
|
}
|
|
|
|
func (f *valueFormatter) Type() string {
|
|
return "valueFormatter"
|
|
}
|
|
|
|
func (f *valueFormatter) Set(spec string) error {
|
|
f.spec = spec
|
|
f.setByUser = true
|
|
switch spec {
|
|
case "null":
|
|
f.fn = formatValueNull
|
|
case "quoted":
|
|
f.fn = formatValueQuoted
|
|
case "pretty":
|
|
// Using "pretty" defaults to base.FormatBytes (just like
|
|
// formatValueQuoted), except with the ability of having the
|
|
// comparer-provided formatter overwrite f.fn if there is one specified. We
|
|
// determine whether to do that overwrite through setByUser.
|
|
f.fn = formatValueQuoted
|
|
f.setByUser = false
|
|
case "size":
|
|
f.fn = formatValueSize
|
|
default:
|
|
if strings.HasPrefix(spec, "pretty:") {
|
|
// Usage: pretty:<comparer-name>
|
|
f.comparer = spec[7:]
|
|
f.fn = formatValueQuoted
|
|
return nil
|
|
}
|
|
if strings.Count(spec, "%") != 1 {
|
|
return errors.Errorf("unknown formatter: %q", errors.Safe(spec))
|
|
}
|
|
f.fn = func(k, v []byte) fmt.Formatter {
|
|
return fmtFormatter{f.spec, v}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *valueFormatter) mustSet(spec string) {
|
|
if err := f.Set(spec); err != nil {
|
|
panic(err)
|
|
}
|
|
f.setByUser = false
|
|
}
|
|
|
|
// Sets the appropriate formatter function for this comparer.
|
|
func (f *valueFormatter) setForComparer(comparerName string, comparers sstable.Comparers) {
|
|
if f.setByUser && len(f.comparer) == 0 {
|
|
// User specified a different formatter, no-op.
|
|
return
|
|
}
|
|
|
|
if len(f.comparer) > 0 {
|
|
// User specified a comparer to reference for formatting, which takes
|
|
// precedence.
|
|
comparerName = f.comparer
|
|
} else if len(comparerName) == 0 {
|
|
return
|
|
}
|
|
|
|
if cmp := comparers[comparerName]; cmp != nil && cmp.FormatValue != nil {
|
|
f.fn = cmp.FormatValue
|
|
}
|
|
}
|
|
|
|
type fmtFormatter struct {
|
|
fmt string
|
|
v []byte
|
|
}
|
|
|
|
func (f fmtFormatter) Format(s fmt.State, c rune) {
|
|
fmt.Fprintf(s, f.fmt, f.v)
|
|
}
|
|
|
|
type nullFormatter struct{}
|
|
|
|
func (nullFormatter) Format(s fmt.State, c rune) {
|
|
}
|
|
|
|
func formatKeyNull(v []byte) fmt.Formatter {
|
|
return nullFormatter{}
|
|
}
|
|
|
|
func formatValueNull(k, v []byte) fmt.Formatter {
|
|
return nullFormatter{}
|
|
}
|
|
|
|
func formatKeyQuoted(v []byte) fmt.Formatter {
|
|
return base.FormatBytes(v)
|
|
}
|
|
|
|
func formatValueQuoted(k, v []byte) fmt.Formatter {
|
|
return base.FormatBytes(v)
|
|
}
|
|
|
|
type sizeFormatter []byte
|
|
|
|
func (v sizeFormatter) Format(s fmt.State, c rune) {
|
|
fmt.Fprintf(s, "<%d>", len(v))
|
|
}
|
|
|
|
func formatKeySize(v []byte) fmt.Formatter {
|
|
return sizeFormatter(v)
|
|
}
|
|
|
|
func formatValueSize(k, v []byte) fmt.Formatter {
|
|
return sizeFormatter(v)
|
|
}
|
|
|
|
func formatKey(w io.Writer, fmtKey keyFormatter, key *base.InternalKey) bool {
|
|
if fmtKey.spec == "null" {
|
|
return false
|
|
}
|
|
fmt.Fprintf(w, "%s", key.Pretty(fmtKey.fn))
|
|
return true
|
|
}
|
|
|
|
func formatSeqNumRange(w io.Writer, start, end uint64) {
|
|
fmt.Fprintf(w, "<#%d-#%d>", start, end)
|
|
}
|
|
|
|
func formatKeyRange(w io.Writer, fmtKey keyFormatter, start, end *base.InternalKey) {
|
|
if fmtKey.spec == "null" {
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "[%s-%s]", start.Pretty(fmtKey.fn), end.Pretty(fmtKey.fn))
|
|
}
|
|
|
|
func formatKeyValue(
|
|
w io.Writer, fmtKey keyFormatter, fmtValue valueFormatter, key *base.InternalKey, value []byte,
|
|
) {
|
|
if key.Kind() == base.InternalKeyKindRangeDelete {
|
|
if fmtKey.spec != "null" {
|
|
fmt.Fprintf(w, "%s-%s#%d,%s",
|
|
fmtKey.fn(key.UserKey), fmtKey.fn(value),
|
|
key.SeqNum(), key.Kind())
|
|
}
|
|
} else {
|
|
needDelimiter := formatKey(w, fmtKey, key)
|
|
if fmtValue.spec != "null" {
|
|
if needDelimiter {
|
|
w.Write([]byte{' '})
|
|
}
|
|
fmt.Fprintf(w, "%s", fmtValue.fn(key.UserKey, value))
|
|
}
|
|
}
|
|
w.Write([]byte{'\n'})
|
|
}
|
|
|
|
func formatSpan(w io.Writer, fmtKey keyFormatter, fmtValue valueFormatter, s *keyspan.Span) {
|
|
if fmtKey.spec != "null" {
|
|
fmt.Fprintf(w, "[%s-%s):\n", fmtKey.fn(s.Start), fmtKey.fn(s.End))
|
|
for _, k := range s.Keys {
|
|
fmt.Fprintf(w, " #%d,%s", k.SeqNum(), k.Kind())
|
|
switch k.Kind() {
|
|
case base.InternalKeyKindRangeKeySet:
|
|
fmt.Fprintf(w, ": %s %s", k.Suffix, fmtValue.fn(s.Start, k.Value))
|
|
case base.InternalKeyKindRangeKeyUnset:
|
|
fmt.Fprintf(w, ": %s", k.Suffix)
|
|
}
|
|
w.Write([]byte{'\n'})
|
|
}
|
|
}
|
|
}
|
|
|
|
func walk(stderr io.Writer, fs vfs.FS, dir string, fn func(path string)) {
|
|
paths, err := fs.List(dir)
|
|
if err != nil {
|
|
fmt.Fprintf(stderr, "%s: %v\n", dir, err)
|
|
return
|
|
}
|
|
sort.Strings(paths)
|
|
for _, part := range paths {
|
|
path := fs.PathJoin(dir, part)
|
|
info, err := fs.Stat(path)
|
|
if err != nil {
|
|
fmt.Fprintf(stderr, "%s: %v\n", path, err)
|
|
continue
|
|
}
|
|
if info.IsDir() {
|
|
walk(stderr, fs, path, fn)
|
|
} else {
|
|
fn(path)
|
|
}
|
|
}
|
|
}
|