github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/tool/manifest.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 "fmt" 9 10 "github.com/petermattis/pebble/internal/base" 11 "github.com/petermattis/pebble/internal/manifest" 12 "github.com/petermattis/pebble/internal/record" 13 "github.com/petermattis/pebble/sstable" 14 "github.com/petermattis/pebble/vfs" 15 "github.com/spf13/cobra" 16 ) 17 18 // manifestT implements manifest-level tools, including both configuration 19 // state and the commands themselves. 20 type manifestT struct { 21 Root *cobra.Command 22 Dump *cobra.Command 23 24 opts *sstable.Options 25 comparers sstable.Comparers 26 fmtKey formatter 27 } 28 29 func newManifest(opts *base.Options, comparers sstable.Comparers) *manifestT { 30 m := &manifestT{ 31 opts: opts, 32 comparers: comparers, 33 } 34 m.fmtKey.mustSet("quoted") 35 36 m.Root = &cobra.Command{ 37 Use: "manifest", 38 Short: "manifest introspection tools", 39 } 40 m.Dump = &cobra.Command{ 41 Use: "dump <manifest-files>", 42 Short: "print manifest contents", 43 Long: ` 44 Print the contents of the MANIFEST files. 45 `, 46 Args: cobra.MinimumNArgs(1), 47 Run: m.runDump, 48 } 49 50 m.Root.AddCommand(m.Dump) 51 52 m.Dump.Flags().Var( 53 &m.fmtKey, "key", "key formatter") 54 return m 55 } 56 57 func (m *manifestT) runDump(cmd *cobra.Command, args []string) { 58 for _, arg := range args { 59 func() { 60 f, err := vfs.Default.Open(arg) 61 if err != nil { 62 fmt.Fprintf(stderr, "%s\n", err) 63 return 64 } 65 defer f.Close() 66 67 fmt.Fprintf(stdout, "%s\n", arg) 68 69 var bve manifest.BulkVersionEdit 70 var cmp *base.Comparer 71 rr := record.NewReader(f, 0 /* logNum */) 72 for { 73 offset := rr.Offset() 74 r, err := rr.Next() 75 if err != nil { 76 fmt.Fprintf(stdout, "%s\n", err) 77 break 78 } 79 80 var ve manifest.VersionEdit 81 err = ve.Decode(r) 82 if err != nil { 83 fmt.Fprintf(stdout, "%s\n", err) 84 break 85 } 86 bve.Accumulate(&ve) 87 88 empty := true 89 fmt.Fprintf(stdout, "%d\n", offset) 90 if ve.ComparerName != "" { 91 empty = false 92 fmt.Fprintf(stdout, " comparer: %s", ve.ComparerName) 93 cmp = m.comparers[ve.ComparerName] 94 if cmp == nil { 95 fmt.Fprintf(stdout, " (unknown)") 96 } 97 fmt.Fprintf(stdout, "\n") 98 } 99 if ve.LogNum != 0 { 100 empty = false 101 fmt.Fprintf(stdout, " log-num: %d\n", ve.LogNum) 102 } 103 if ve.PrevLogNum != 0 { 104 empty = false 105 fmt.Fprintf(stdout, " prev-log-num: %d\n", ve.PrevLogNum) 106 } 107 if ve.LastSeqNum != 0 { 108 empty = false 109 fmt.Fprintf(stdout, " last-seq-num: %d\n", ve.LastSeqNum) 110 } 111 for df := range ve.DeletedFiles { 112 empty = false 113 fmt.Fprintf(stdout, " deleted: L%d %d\n", df.Level, df.FileNum) 114 } 115 for _, nf := range ve.NewFiles { 116 empty = false 117 fmt.Fprintf(stdout, " added: L%d %d:%d", 118 nf.Level, nf.Meta.FileNum, nf.Meta.Size) 119 formatKeyRange(stdout, m.fmtKey, &nf.Meta.Smallest, &nf.Meta.Largest) 120 fmt.Fprintf(stdout, "\n") 121 } 122 if empty { 123 // NB: An empty version edit can happen if we log a version edit with 124 // a zero field. RocksDB does this with a version edit that contains 125 // `LogNum == 0`. 126 fmt.Fprintf(stdout, " <empty>\n") 127 } 128 } 129 130 if cmp != nil { 131 v, err := bve.Apply(m.opts, nil, cmp.Compare) 132 if err != nil { 133 fmt.Fprintf(stdout, "%s\n", err) 134 return 135 } 136 for level := range v.Files { 137 fmt.Fprintf(stdout, "--- L%d ---\n", level) 138 for j := range v.Files[level] { 139 f := &v.Files[level][j] 140 fmt.Fprintf(stdout, " %d:%d", f.FileNum, f.Size) 141 formatKeyRange(stdout, m.fmtKey, &f.Smallest, &f.Largest) 142 fmt.Fprintf(stdout, "\n") 143 } 144 } 145 } 146 }() 147 } 148 }