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  }