diff --git a/blockstore/splitstore/README.md b/blockstore/splitstore/README.md index 4efd6f61d1d..f69a056ca43 100644 --- a/blockstore/splitstore/README.md +++ b/blockstore/splitstore/README.md @@ -119,6 +119,7 @@ TBD -- see [#6577](https://github.com/filecoin-project/lotus/issues/6577) It can also optionally compact/gc the coldstore after the copy (with the `--gc-coldstore` flag) and automatically rewrite the lotus config to disable splitstore (with the `--rewrite-config` flag). Note: the node *must be stopped* before running this command. +- `clear` -- clears a splitstore installation for restart from snapshot. - `check` -- asynchronously runs a basic healthcheck on the splitstore. The results are appended to `/datastore/splitstore/check.txt`. - `info` -- prints some basic information about the splitstore. diff --git a/cmd/lotus-shed/splitstore.go b/cmd/lotus-shed/splitstore.go index c2363c65583..4f668888eaf 100644 --- a/cmd/lotus-shed/splitstore.go +++ b/cmd/lotus-shed/splitstore.go @@ -11,6 +11,7 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/urfave/cli/v2" + "go.uber.org/multierr" "golang.org/x/sync/errgroup" "golang.org/x/xerrors" @@ -29,6 +30,7 @@ var splitstoreCmd = &cli.Command{ Description: "splitstore utilities", Subcommands: []*cli.Command{ splitstoreRollbackCmd, + splitstoreClearCmd, splitstoreCheckCmd, splitstoreInfoCmd, }, @@ -91,10 +93,16 @@ var splitstoreRollbackCmd = &cli.Command{ return xerrors.Errorf("error copying hotstore to coldstore: %w", err) } + fmt.Println("clearing splitstore directory...") + err = clearSplitstoreDir(lr) + if err != nil { + return xerrors.Errorf("error clearing splitstore directory: %w", err) + } + fmt.Println("deleting splitstore directory...") err = deleteSplitstoreDir(lr) if err != nil { - return xerrors.Errorf("error deleting splitstore directory: %w", err) + log.Warnf("error deleting splitstore directory: %s", err) } fmt.Println("deleting splitstore keys from metadata datastore...") @@ -118,6 +126,71 @@ var splitstoreRollbackCmd = &cli.Command{ }, } +var splitstoreClearCmd = &cli.Command{ + Name: "clear", + Description: "clears a splitstore installation for restart from snapshot", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.BoolFlag{ + Name: "keys-only", + Usage: "only delete splitstore keys", + }, + }, + Action: func(cctx *cli.Context) error { + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("error opening fs repo: %w", err) + } + + exists, err := r.Exists() + if err != nil { + return err + } + if !exists { + return xerrors.Errorf("lotus repo doesn't exist") + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return xerrors.Errorf("error locking repo: %w", err) + } + defer lr.Close() //nolint:errcheck + + cfg, err := lr.Config() + if err != nil { + return xerrors.Errorf("error getting config: %w", err) + } + + fncfg, ok := cfg.(*config.FullNode) + if !ok { + return xerrors.Errorf("wrong config type: %T", cfg) + } + + if !fncfg.Chainstore.EnableSplitstore { + return xerrors.Errorf("splitstore is not enabled") + } + + if !cctx.Bool("keys-only") { + fmt.Println("clearing splitstore directory...") + err = clearSplitstoreDir(lr) + if err != nil { + return xerrors.Errorf("error clearing splitstore directory: %w", err) + } + } + + fmt.Println("deleting splitstore keys from metadata datastore...") + err = deleteSplitstoreKeys(lr) + if err != nil { + return xerrors.Errorf("error deleting splitstore keys: %w", err) + } + + return nil + }, +} + func copyHotstoreToColdstore(lr repo.LockedRepo, gcColdstore bool) error { repoPath := lr.Path() dataPath := filepath.Join(repoPath, "datastore") @@ -224,6 +297,30 @@ func deleteSplitstoreDir(lr repo.LockedRepo) error { return os.RemoveAll(path) } +func clearSplitstoreDir(lr repo.LockedRepo) error { + path, err := lr.SplitstorePath() + if err != nil { + return xerrors.Errorf("error getting splitstore path: %w", err) + } + + entries, err := os.ReadDir(path) + if err != nil { + return xerrors.Errorf("error reading splitstore directory %s: %W", path, err) + } + + var result error + for _, e := range entries { + target := filepath.Join(path, e.Name()) + err = os.RemoveAll(target) + if err != nil { + log.Errorf("error removing %s: %s", target, err) + result = multierr.Append(result, err) + } + } + + return result +} + func deleteSplitstoreKeys(lr repo.LockedRepo) error { ds, err := lr.Datastore(context.TODO(), "/metadata") if err != nil {