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 }