Skip to content

Commit

Permalink
cmd: migrate 'surgery copy-page' command to cobra style command
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Wang <[email protected]>
  • Loading branch information
ahrtr committed May 9, 2023
1 parent 8b1ee10 commit 6e12e08
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 198 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func newSurgeryCobraCommand() *cobra.Command {

surgeryCmd.AddCommand(newSurgeryRevertMetaPageCommand())
surgeryCmd.AddCommand(newSurgeryCopyPageCommand())
surgeryCmd.AddCommand(newSurgeryClearPageCommand())
surgeryCmd.AddCommand(newSurgeryClearPageElementsCommand())
surgeryCmd.AddCommand(newSurgeryFreelistCommand())

Expand Down Expand Up @@ -183,6 +184,54 @@ func (o *surgeryClearPageElementsOptions) Validate() error {
return nil
}

func newSurgeryClearPageCommand() *cobra.Command {
cfg := defaultSurgeryOptions()
clearPageCmd := &cobra.Command{
Use: "clear-page <bbolt-file> [options]",
Short: "Clears all 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: func(cmd *cobra.Command, args []string) error {
return surgeryClearPageFunc(args[0], cfg)
},
}

clearPageCmd.Flags().StringVar(&cfg.surgeryTargetDBFilePath, "output", "", "path to the target db file")
clearPageCmd.Flags().Uint64VarP(&cfg.surgeryPageId, "pageId", "", 0, "page id")

return clearPageCmd
}

func surgeryClearPageFunc(srcDBPath string, cfg surgeryOptions) error {
if err := common.CopyFile(srcDBPath, cfg.surgeryTargetDBFilePath); err != nil {
return fmt.Errorf("[clear-page] copy file failed: %w", err)
}

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

needAbandonFreelist, err := surgeon.ClearPage(cfg.surgeryTargetDBFilePath, common.Pgid(cfg.surgeryPageId))
if err != nil {
return fmt.Errorf("clear-page 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, "The page (%d) was cleared\n", cfg.surgeryPageId)
return nil
}

func newSurgeryClearPageElementsCommand() *cobra.Command {
var o surgeryClearPageElementsOptions
clearElementCmd := &cobra.Command{
Expand Down Expand Up @@ -227,9 +276,6 @@ func surgeryClearPageElementFunc(srcDBPath string, cfg surgeryClearPageElementsO
return nil
}

// TODO(ahrtr): add `bbolt surgery freelist rebuild/check ...` commands,
// and move all `surgery freelist` commands into a separate file,
// e.g command_surgery_freelist.go.
func newSurgeryFreelistCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "freelist <subcommand>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ func TestSurgery_CopyPage(t *testing.T) {
assert.Equal(t, pageDataWithoutPageId(srcPageId3Data), pageDataWithoutPageId(dstPageId2Data))
}

// TODO(ahrtr): add test case below for `surgery clear-page` command:
// 1. The page is a branch page. All its children should become free pages.
func TestSurgery_ClearPage(t *testing.T) {
pageSize := 4096
db := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: pageSize})
srcPath := db.Path()

// Insert some sample data
t.Log("Insert some sample data")
err := db.Fill([]byte("data"), 1, 20,
func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
func(tx int, k int) []byte { return make([]byte, 10) },
)
require.NoError(t, err)

defer requireDBNoChange(t, dbData(t, srcPath), srcPath)

// clear page 3
t.Log("clear page 3")
rootCmd := main.NewRootCommand()
output := filepath.Join(t.TempDir(), "dstdb")
rootCmd.SetArgs([]string{
"surgery", "clear-page", srcPath,
"--output", output,
"--pageId", "3",
})
err = rootCmd.Execute()
require.NoError(t, err)

t.Log("Verify result")
dstPageId3Data := readPage(t, output, 3, pageSize)

p := common.LoadPage(dstPageId3Data)
assert.Equal(t, uint16(0), p.Count())
assert.Equal(t, uint32(0), p.Overflow())
}

func TestSurgery_ClearPageElements_Without_Overflow(t *testing.T) {
testCases := []struct {
name string
Expand Down
2 changes: 0 additions & 2 deletions cmd/bbolt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ func (m *Main) Run(args ...string) error {
return newPagesCommand(m).Run(args[1:]...)
case "stats":
return newStatsCommand(m).Run(args[1:]...)
case "surgery":
return newSurgeryCommand(m).Run(args[1:]...)
default:
return ErrUnknownCommand
}
Expand Down
146 changes: 0 additions & 146 deletions cmd/bbolt/surgery_commands.go

This file was deleted.

47 changes: 0 additions & 47 deletions cmd/bbolt/surgery_commands_test.go

This file was deleted.

0 comments on commit 6e12e08

Please sign in to comment.