github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/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 "os" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/petermattis/pebble/internal/base" 17 ) 18 19 var stdout = io.Writer(os.Stdout) 20 var stderr = io.Writer(os.Stderr) 21 var osExit = os.Exit 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 formatter struct { 54 spec string 55 fn func(w io.Writer, v []byte) 56 } 57 58 func (f *formatter) String() string { 59 return f.spec 60 } 61 62 func (f *formatter) Type() string { 63 return "formatter" 64 } 65 66 func (f *formatter) Set(spec string) error { 67 f.spec = spec 68 switch spec { 69 case "null": 70 f.fn = formatNull 71 case "quoted": 72 f.fn = formatQuoted 73 case "size": 74 f.fn = formatSize 75 default: 76 if strings.Count(spec, "%") != 1 { 77 return fmt.Errorf("unknown formatter: %q", spec) 78 } 79 f.fn = func(w io.Writer, v []byte) { 80 fmt.Fprintf(w, f.spec, v) 81 } 82 } 83 return nil 84 } 85 86 func (f *formatter) mustSet(spec string) { 87 if err := f.Set(spec); err != nil { 88 panic(err) 89 } 90 } 91 92 func formatNull(w io.Writer, v []byte) { 93 } 94 95 func formatQuoted(w io.Writer, v []byte) { 96 q := strconv.AppendQuote(make([]byte, 0, len(v)), string(v)) 97 q = q[1 : len(q)-1] 98 w.Write(q) 99 } 100 101 func formatSize(w io.Writer, v []byte) { 102 fmt.Fprintf(w, "<%d>", len(v)) 103 } 104 105 func formatKey(w io.Writer, fmtKey formatter, key *base.InternalKey) bool { 106 if fmtKey.spec == "null" { 107 return false 108 } 109 fmtKey.fn(w, key.UserKey) 110 fmt.Fprintf(w, "#%d,%d", key.SeqNum(), key.Kind()) 111 return true 112 } 113 114 func formatKeyRange(w io.Writer, fmtKey formatter, start, end *base.InternalKey) { 115 if fmtKey.spec == "null" { 116 return 117 } 118 w.Write([]byte{'['}) 119 formatKey(w, fmtKey, start) 120 w.Write([]byte{'-'}) 121 formatKey(w, fmtKey, end) 122 w.Write([]byte{']'}) 123 } 124 125 func formatKeyValue( 126 w io.Writer, fmtKey formatter, fmtValue formatter, key *base.InternalKey, value []byte, 127 ) { 128 if key.Kind() == base.InternalKeyKindRangeDelete { 129 if fmtKey.spec != "null" { 130 fmtKey.fn(w, key.UserKey) 131 w.Write([]byte{'-'}) 132 fmtKey.fn(w, value) 133 fmt.Fprintf(w, "#%d,%d", key.SeqNum(), key.Kind()) 134 } 135 } else { 136 needDelimiter := formatKey(w, fmtKey, key) 137 if fmtValue.spec != "null" { 138 if needDelimiter { 139 w.Write([]byte{' '}) 140 } 141 fmtValue.fn(stdout, value) 142 } 143 } 144 w.Write([]byte{'\n'}) 145 }