Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cobra style surgery clear-page-elements command #417

Merged
merged 8 commits into from
Mar 28, 2023
24 changes: 24 additions & 0 deletions cmd/bbolt/command_root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"github.com/spf13/cobra"
)

const (
cliName = "bbolt"
cliDescription = "A simple command line tool for inspecting bbolt databases"
)

func NewRootCommand() *cobra.Command {
rootCmd := &cobra.Command{
Use: cliName,
Short: cliDescription,
Version: "dev",
}

rootCmd.AddCommand(
newSurgeryCobraCommand(),
)

return rootCmd
}
80 changes: 80 additions & 0 deletions cmd/bbolt/command_surgery_cobra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package main

import (
"errors"
"fmt"
"os"

"github.com/spf13/cobra"

"go.etcd.io/bbolt/internal/common"
"go.etcd.io/bbolt/internal/surgeon"
)

var (
surgeryTargetDBFilePath string
surgeryPageId uint64
surgeryStartElementIdx int
surgeryEndElementIdx int
)

func newSurgeryCobraCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "surgery <subcommand>",
Short: "surgery related commands",
}

cmd.AddCommand(newSurgeryClearPageElementsCommand())

return cmd
}

func newSurgeryClearPageElementsCommand() *cobra.Command {
clearElementCmd := &cobra.Command{
Use: "clear-page-elements <bbolt-file> [options]",
Short: "Clears elements from the given page, which can be a branch or leaf page",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("db file path not provided")
}
if len(args) > 1 {
return errors.New("too many arguments")
}
return nil
},

RunE: surgeryClearPageElementFunc,
}

clearElementCmd.Flags().StringVar(&surgeryTargetDBFilePath, "output", "", "path to the target db file")
clearElementCmd.Flags().Uint64VarP(&surgeryPageId, "pageId", "", 0, "page id")
clearElementCmd.Flags().IntVarP(&surgeryStartElementIdx, "from-index", "", 0, "start element index (included) to clear, starting from 0")
clearElementCmd.Flags().IntVarP(&surgeryEndElementIdx, "to-index", "", 0, "end element index (excluded) to clear, starting from 0, -1 means to the end of page")

return clearElementCmd
}

func surgeryClearPageElementFunc(cmd *cobra.Command, args []string) error {
srcDBPath := args[0]

if err := copyFile(srcDBPath, surgeryTargetDBFilePath); err != nil {
ahrtr marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("[clear-page-element] copy file failed: %w", err)
}

if surgeryPageId < 2 {
return fmt.Errorf("the pageId must be at least 2, but got %d", surgeryPageId)
}

needAbandonFreelist, err := surgeon.ClearPageElements(surgeryTargetDBFilePath, common.Pgid(surgeryPageId), surgeryStartElementIdx, surgeryEndElementIdx, false)
if err != nil {
return fmt.Errorf("clear-page-element command failed: %w", err)
}

if needAbandonFreelist {
fmt.Fprintf(os.Stdout, "WARNING: The clearing has abandoned some pages that are not yet referenced from free list.\n")
fmt.Fprintf(os.Stdout, "Please consider executing `./bbolt surgery abandon-freelist ...`\n")
}

fmt.Fprintf(os.Stdout, "All elements in [%d, %d) in page %d were cleared\n", surgeryStartElementIdx, surgeryEndElementIdx, surgeryPageId)
return nil
}
Loading