package control import ( "fmt" rawclient "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key" commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control" "github.com/mr-tron/base58" "github.com/spf13/cobra" ) const ( fillPercentFlag = "fill_percent" ) var shardsRebuildCmd = &cobra.Command{ Use: "rebuild", Short: "Rebuild shards", Long: "Rebuild reclaims storage occupied by dead objects and adjusts the storage structure according to the configuration (for blobovnicza only now)", Run: shardsRebuild, } func shardsRebuild(cmd *cobra.Command, _ []string) { pk := key.Get(cmd) req := &control.StartShardRebuildRequest{ Body: &control.StartShardRebuildRequest_Body{ Shard_ID: getShardIDList(cmd), TargetFillPercent: getFillPercentValue(cmd), ConcurrencyLimit: getConcurrencyValue(cmd), }, } signRequest(cmd, pk, req) cli := getClient(cmd, pk) var resp *control.StartShardRebuildResponse var err error err = cli.ExecRaw(func(client *rawclient.Client) error { resp, err = control.StartShardRebuild(client, req) return err }) commonCmd.ExitOnErr(cmd, "rpc error: %w", err) verifyResponse(cmd, resp.GetSignature(), resp.GetBody()) var success, failed uint for _, res := range resp.GetBody().GetResults() { if res.GetSuccess() { success++ cmd.Printf("Shard %s: OK\n", base58.Encode(res.GetShard_ID())) } else { failed++ cmd.Printf("Shard %s: failed with error %q\n", base58.Encode(res.GetShard_ID()), res.GetError()) } } cmd.Printf("Total: %d success, %d failed\n", success, failed) } func getFillPercentValue(cmd *cobra.Command) uint32 { v, _ := cmd.Flags().GetUint32(fillPercentFlag) if v <= 0 || v > 100 { commonCmd.ExitOnErr(cmd, "invalid fill_percent value", fmt.Errorf("fill_percent value must be (0, 100], current value: %d", v)) } return v } func getConcurrencyValue(cmd *cobra.Command) uint32 { v, _ := cmd.Flags().GetUint32(concurrencyFlag) if v <= 0 || v > 10000 { commonCmd.ExitOnErr(cmd, "invalid concurrency value", fmt.Errorf("concurrency value must be (0, 10 000], current value: %d", v)) } return v } func initControlShardRebuildCmd() { initControlFlags(shardsRebuildCmd) flags := shardsRebuildCmd.Flags() flags.StringSlice(shardIDFlag, nil, "List of shard IDs in base58 encoding") flags.Bool(shardAllFlag, false, "Process all shards") flags.Uint32(fillPercentFlag, 80, "Target fill percent to reclaim space") flags.Uint32(concurrencyFlag, 20, "Maximum count of concurrently rebuilding files") setShardModeCmd.MarkFlagsMutuallyExclusive(shardIDFlag, shardAllFlag) }