github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/tool/remotecat.go (about)

     1  // Copyright 2023 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  	"io"
    10  	"sort"
    11  
    12  	"github.com/cockroachdb/pebble"
    13  	"github.com/cockroachdb/pebble/internal/base"
    14  	"github.com/cockroachdb/pebble/objstorage"
    15  	"github.com/cockroachdb/pebble/objstorage/objstorageprovider/remoteobjcat"
    16  	"github.com/cockroachdb/pebble/record"
    17  	"github.com/spf13/cobra"
    18  )
    19  
    20  // remoteCatalogT implements tools for the remote object catalog.
    21  type remoteCatalogT struct {
    22  	Root *cobra.Command
    23  	Dump *cobra.Command
    24  
    25  	verbose bool
    26  	opts    *pebble.Options
    27  }
    28  
    29  func newRemoteCatalog(opts *pebble.Options) *remoteCatalogT {
    30  	m := &remoteCatalogT{
    31  		opts: opts,
    32  	}
    33  
    34  	m.Root = &cobra.Command{
    35  		Use:   "remotecat",
    36  		Short: "remote object catalog introspection tools",
    37  	}
    38  
    39  	// Add dump command
    40  	m.Dump = &cobra.Command{
    41  		Use:   "dump <remote-catalog-files>",
    42  		Short: "print remote object catalog contents",
    43  		Long: `
    44  Print the contents of the REMOTE-OBJ-CATALOG files.
    45  `,
    46  		Args: cobra.MinimumNArgs(1),
    47  		Run:  m.runDump,
    48  	}
    49  	m.Dump.Flags().BoolVarP(&m.verbose, "verbose", "v", false, "show each record in the catalog")
    50  	m.Root.AddCommand(m.Dump)
    51  
    52  	return m
    53  }
    54  
    55  func (m *remoteCatalogT) runDump(cmd *cobra.Command, args []string) {
    56  	for _, arg := range args {
    57  		err := m.runDumpOne(cmd.OutOrStdout(), arg)
    58  		if err != nil {
    59  			fmt.Fprintf(cmd.OutOrStderr(), "%s\n", err)
    60  		}
    61  	}
    62  }
    63  
    64  func (m *remoteCatalogT) runDumpOne(stdout io.Writer, filename string) error {
    65  	f, err := m.opts.FS.Open(filename)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	var creatorID objstorage.CreatorID
    71  	objects := make(map[base.DiskFileNum]remoteobjcat.RemoteObjectMetadata)
    72  
    73  	fmt.Fprintf(stdout, "%s\n", filename)
    74  	var editIdx int
    75  	rr := record.NewReader(f, 0 /* logNum */)
    76  	for {
    77  		offset := rr.Offset()
    78  		r, err := rr.Next()
    79  		if err == io.EOF {
    80  			break
    81  		} else if err != nil {
    82  			return err
    83  		}
    84  
    85  		var ve remoteobjcat.VersionEdit
    86  		err = ve.Decode(r)
    87  		if err != nil {
    88  			return err
    89  		}
    90  
    91  		if m.verbose {
    92  			fmt.Fprintf(stdout, "%d/%d\n", offset, editIdx)
    93  			if ve.CreatorID.IsSet() {
    94  				fmt.Fprintf(stdout, "  CreatorID: %s\n", ve.CreatorID)
    95  			}
    96  			if len(ve.NewObjects) > 0 {
    97  				fmt.Fprintf(stdout, "  NewObjects:\n")
    98  				for _, m := range ve.NewObjects {
    99  					fmt.Fprintf(
   100  						stdout, "    %s  CreatorID: %s  CreatorFileNum: %s  Locator: %q CustomObjectName: %q\n",
   101  						m.FileNum, m.CreatorID, m.CreatorFileNum, m.Locator, m.CustomObjectName,
   102  					)
   103  				}
   104  			}
   105  			if len(ve.DeletedObjects) > 0 {
   106  				fmt.Fprintf(stdout, "  DeletedObjects:\n")
   107  				for _, n := range ve.DeletedObjects {
   108  					fmt.Fprintf(stdout, "    %s\n", n)
   109  				}
   110  			}
   111  		}
   112  		editIdx++
   113  		if err := ve.Apply(&creatorID, objects); err != nil {
   114  			return err
   115  		}
   116  	}
   117  	fmt.Fprintf(stdout, "CreatorID: %v\n", creatorID)
   118  	var filenums []base.DiskFileNum
   119  	for n := range objects {
   120  		filenums = append(filenums, n)
   121  	}
   122  	sort.Slice(filenums, func(i, j int) bool {
   123  		return filenums[i].FileNum() < filenums[j].FileNum()
   124  	})
   125  	fmt.Fprintf(stdout, "Objects:\n")
   126  	for _, n := range filenums {
   127  		m := objects[n]
   128  		fmt.Fprintf(
   129  			stdout, "    %s  CreatorID: %s  CreatorFileNum: %s  Locator: %q CustomObjectName: %q\n",
   130  			n, m.CreatorID, m.CreatorFileNum, m.Locator, m.CustomObjectName,
   131  		)
   132  	}
   133  	return nil
   134  }