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 base.SeqNum) {
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 : }
|