diff --git a/tools-v2/README.md b/tools-v2/README.md index 5ee19eb6ae..b9fea277f8 100644 --- a/tools-v2/README.md +++ b/tools-v2/README.md @@ -89,6 +89,7 @@ A tool for CurveFS & CurveBs. - [check copyset](#check-copyset-1) - [check chunkserver](#check-chunkserver) - [check server](#check-server) + - [check consistency](#check-consistency) - [snapshot](#snapshot) - [snapshot copyset](#snapshot-copyset) - [Comparison of old and new commands](#comparison-of-old-and-new-commands) @@ -1871,6 +1872,26 @@ Output: +--------+-----------+-------+------------------+ ``` +##### check consistency + +check the file consistency + +Usage: + +```shell +curve bs check consistency --path /test +``` + +Output: + +```shell ++--------+--------+------------+ +| NAME | STATUS | EXPLAIN | ++--------+--------+------------+ +| /test | ok | - | ++--------+--------+------------+ +``` + #### snapshot ##### snapshot copyset @@ -1971,8 +1992,8 @@ Output: | curve_ops_tool list-may-broken-vol | curve bs list may-broken-vol | | curve_ops_tool rapid-leader-schedule | curve bs update leader-schedule | | curve_ops_tool do-snapshot-all | curve bs snapshot --all | -| curve_ops_tool check-chunkserver | curbe bs check chunkserver | +| curve_ops_tool check-chunkserver | curve bs check chunkserver | | curve_ops_tool status | | -| curve_ops_tool check-consistency | | +| curve_ops_tool check-consistency | curve bs check consistency | | curve_ops_tool check-server | curve bs check server | diff --git a/tools-v2/internal/error/error.go b/tools-v2/internal/error/error.go index a4737ba33d..a8d91a9cc9 100644 --- a/tools-v2/internal/error/error.go +++ b/tools-v2/internal/error/error.go @@ -487,6 +487,12 @@ var ( ErrBsGetFormatStatus = func() *CmdError { return NewInternalCmdError(75, "get format status fail, err: %s") } + ErrBsGetSegmentInfo = func() *CmdError { + return NewInternalCmdError(76, "get segment info fail, err: %s") + } + ErrBsGetChunkHash = func() *CmdError { + return NewInternalCmdError(77, "get chunk hash fail, err: %s") + } // http error ErrHttpUnreadableResult = func() *CmdError { diff --git a/tools-v2/pkg/cli/command/curvebs/check/check.go b/tools-v2/pkg/cli/command/curvebs/check/check.go index 17617c529e..0e5bd26d49 100644 --- a/tools-v2/pkg/cli/command/curvebs/check/check.go +++ b/tools-v2/pkg/cli/command/curvebs/check/check.go @@ -25,6 +25,7 @@ package check import ( basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/check/chunkserver" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/check/consistency" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/check/copyset" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/check/operator" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/check/server" @@ -43,6 +44,7 @@ func (checkCmd *CheckCommand) AddSubCommands() { operator.NewOperatorCommand(), server.NewServerCommand(), chunkserver.NewChunkserverCommand(), + consistency.NewConsistencyCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/check/consistency/consistency.go b/tools-v2/pkg/cli/command/curvebs/check/consistency/consistency.go new file mode 100644 index 0000000000..a0f71ee0ae --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/check/consistency/consistency.go @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: tools-v2 + * Created Date: 2023-07-13 + * Author: victorseptember + */ + +package consistency + +import ( + "fmt" + "strconv" + "strings" + + mapset "github.com/deckarep/golang-set/v2" + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + cobrautil "github.com/opencurve/curve/tools-v2/internal/utils" + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/query/chunk" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/query/chunkserver" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/query/seginfo" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/status/copyset" + "github.com/opencurve/curve/tools-v2/pkg/config" + "github.com/opencurve/curve/tools-v2/pkg/output" + "github.com/spf13/cobra" +) + +const ( + consistencyExample = `$ curve bs check consistency --path file_path` +) + +type ConsistencyCommand struct { + basecmd.FinalCurveCmd +} + +var _ basecmd.FinalCurveCmdFunc = (*ConsistencyCommand)(nil) + +func NewConsistencyCommand() *cobra.Command { + return NewCheckConsistencyCommand().Cmd +} + +func NewCheckConsistencyCommand() *ConsistencyCommand { + consistencyCmd := &ConsistencyCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "consistency", + Short: "check the file consistency", + Example: consistencyExample, + }} + basecmd.NewFinalCurveCli(&consistencyCmd.FinalCurveCmd, consistencyCmd) + return consistencyCmd +} + +func (cCmd *ConsistencyCommand) AddFlags() { + config.AddBsMdsFlagOption(cCmd.Cmd) + config.AddRpcTimeoutFlag(cCmd.Cmd) + config.AddRpcRetryTimesFlag(cCmd.Cmd) + config.AddBsPathRequiredFlag(cCmd.Cmd) + config.AddHttpTimeoutFlag(cCmd.Cmd) + config.AddBsCheckHashOptionFlag(cCmd.Cmd) +} + +func (cCmd *ConsistencyCommand) Init(cmd *cobra.Command, args []string) error { + segmentInfoResponse, err := seginfo.GetSegmentInfo(cCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + logicalpoolIds := make([]string, 0) + copysetIds := make([]string, 0) + chunkIds := make([]string, 0) + + for _, segment := range segmentInfoResponse { + for _, chunk := range segment.GetChunks() { + logicalpoolId := segment.GetLogicalPoolID() + copysetId := chunk.GetCopysetID() + chunkId := chunk.GetChunkID() + logicalpoolIds = append(logicalpoolIds, fmt.Sprintf("%d", logicalpoolId)) + copysetIds = append(copysetIds, fmt.Sprintf("%d", copysetId)) + chunkIds = append(chunkIds, fmt.Sprintf("%d", chunkId)) + } + } + + if len(logicalpoolIds) == 0 || len(copysetIds) == 0 { + return fmt.Errorf("the number of logicalpoolid or copysetid is empty") + } + config.AddBsCopysetIdSliceRequiredFlag(cCmd.Cmd) + config.AddBsLogicalPoolIdSliceRequiredFlag(cCmd.Cmd) + cCmd.Cmd.ParseFlags([]string{ + fmt.Sprintf("--%s", config.CURVEBS_LOGIC_POOL_ID), strings.Join(logicalpoolIds, ","), + fmt.Sprintf("--%s", config.CURVEBS_COPYSET_ID), strings.Join(copysetIds, ","), + }) + + key2Location, err := chunkserver.GetChunkServerListInCopySets(cCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + logicalpoolidList, errParse := cobrautil.StringList2Uint32List(logicalpoolIds) + if errParse != nil { + return fmt.Errorf("parse logicalpoolid%v fail", logicalpoolIds) + } + copysetidList, errParse := cobrautil.StringList2Uint32List(copysetIds) + if errParse != nil { + return fmt.Errorf("parse copysetid%v fail", copysetIds) + } + + // check copyset raft status + chunkServerLocationSet := mapset.NewSet[string]() + key2Address := make(map[uint64][]string) + copysetKeysSet := mapset.NewSet[uint64]() + addr2Id := make(map[string]uint32) + for i := 0; i < len(logicalpoolidList); i++ { + logicpoolid := logicalpoolidList[i] + copysetid := copysetidList[i] + key := cobrautil.GetCopysetKey(uint64(logicpoolid), uint64(copysetid)) + if copysetKeysSet.Contains(key) { + continue + } + copysetKeysSet.Add(key) + for _, cs := range key2Location[key] { + address := fmt.Sprintf("%s:%d", *cs.HostIp, *cs.Port) + key2Address[key] = append(key2Address[key], address) + chunkServerLocationSet.Add(address) + addr2Id[address] = *cs.ChunkServerID + } + } + + cs := copyset.NewCopyset() + filename := config.GetBsFlagString(cmd, config.CURVEBS_PATH) + status, explain, err2 := copyset.CheckCopysetsInChunkServers( + chunkServerLocationSet.ToSlice(), addr2Id, cs, copysetKeysSet, cmd) + if err2 != nil { + return fmt.Errorf("CheckCopysetsInChunkServers fail") + } + + // chech chunk hash + checkHash := config.GetBsFlagBool(cCmd.Cmd, config.CURVEBS_CHECK_HASH) + if checkHash { + config.AddBsPeersAddressFlag(cCmd.Cmd) + config.AddBsChunkIdRequiredFlag(cCmd.Cmd) + config.AddBsChunkSizeRequiredFlag(cCmd.Cmd) + chunksize := segmentInfoResponse[0].GetChunkSize() + for i := 0; i < len(logicalpoolIds); i++ { + key := cobrautil.GetCopysetKey(uint64(logicalpoolidList[i]), uint64(copysetidList[i])) + config.ResetStringSliceFlag(cCmd.Cmd.Flag(config.CURVEBS_LOGIC_POOL_ID), logicalpoolIds[i]) + config.ResetStringSliceFlag(cCmd.Cmd.Flag(config.CURVEBS_COPYSET_ID), copysetIds[i]) + cCmd.Cmd.ParseFlags([]string{ + fmt.Sprintf("--%s", config.CURVEBS_CHUNK_ID), chunkIds[i], + fmt.Sprintf("--%s", config.CURVEBS_CHUNK_SIZE), fmt.Sprintf("%d", chunksize), + fmt.Sprintf("--%s", config.CURVEBS_PEERS_ADDRESS), strings.Join(key2Address[key], ","), + }) + result, checkHashExplain, err := chunk.GetChunkHash(cCmd.Cmd) + if err != nil { + return fmt.Errorf("GetChunkHash fail") + } + if !result { + status = cobrautil.CopysetHealthStatus_Str[int32(cobrautil.HEALTH_ERROR)] + explain += fmt.Sprintf("copyset %s chunkID %s %s.\n", + strconv.FormatUint(key, 10), chunkIds[i], checkHashExplain) + } + } + } + cCmd.TableNew.Append([]string{filename, status, explain}) + header := []string{cobrautil.ROW_NAME, cobrautil.ROW_STATUS, cobrautil.ROW_EXPLAIN} + cCmd.SetHeader(header) + + return nil +} + +func (cCmd *ConsistencyCommand) RunCommand(cmd *cobra.Command, args []string) error { + return nil +} + +func (cCmd *ConsistencyCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutputPlain(&cCmd.FinalCurveCmd) +} + +func (cCmd *ConsistencyCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&cCmd.FinalCurveCmd) +} diff --git a/tools-v2/pkg/cli/command/curvebs/query/chunk/chunkhash.go b/tools-v2/pkg/cli/command/curvebs/query/chunk/chunkhash.go new file mode 100644 index 0000000000..5745472fe7 --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/query/chunk/chunkhash.go @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: tools-v2 + * Created Date: 2023-10-03 + * Author: victorseptember + */ + +package chunk + +import ( + "context" + "fmt" + "strings" + + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + "github.com/opencurve/curve/tools-v2/pkg/config" + "github.com/opencurve/curve/tools-v2/pkg/output" + "github.com/opencurve/curve/tools-v2/proto/proto/chunk" + "github.com/spf13/cobra" + "google.golang.org/grpc" +) + +type GetChunkHashRpc struct { + Info *basecmd.Rpc + Request *chunk.GetChunkHashRequest + mdsClient chunk.ChunkServiceClient +} + +var _ basecmd.RpcFunc = (*GetChunkHashRpc)(nil) // check interface + +func (gRpc *GetChunkHashRpc) NewRpcClient(cc grpc.ClientConnInterface) { + gRpc.mdsClient = chunk.NewChunkServiceClient(cc) +} + +func (gRpc *GetChunkHashRpc) Stub_Func(ctx context.Context) (interface{}, error) { + return gRpc.mdsClient.GetChunkHash(ctx, gRpc.Request) +} + +type GetChunkHashCommand struct { + basecmd.FinalCurveCmd + Rpc []*GetChunkHashRpc + result bool + explain string +} + +var _ basecmd.FinalCurveCmdFunc = (*GetChunkHashCommand)(nil) + +func NewChunkHashCommand() *cobra.Command { + return NewGetChunkHashCommand().Cmd +} + +func NewGetChunkHashCommand() *GetChunkHashCommand { + chunkHashCmd := &GetChunkHashCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{}, + result: true, + } + basecmd.NewFinalCurveCli(&chunkHashCmd.FinalCurveCmd, chunkHashCmd) + return chunkHashCmd +} + +func (cCmd *GetChunkHashCommand) Init(cmd *cobra.Command, args []string) error { + timeout := config.GetFlagDuration(cCmd.Cmd, config.RPCTIMEOUT) + retrytimes := config.GetFlagInt32(cCmd.Cmd, config.RPCRETRYTIMES) + copysetid := config.GetBsFlagUint32(cCmd.Cmd, config.CURVEBS_COPYSET_ID) + logicalpoolid := config.GetBsFlagUint32(cCmd.Cmd, config.CURVEBS_LOGIC_POOL_ID) + chunkid := config.GetBsFlagUint64(cCmd.Cmd, config.CURVEBS_CHUNK_ID) + chunksize := config.GetBsFlagUint32(cCmd.Cmd, config.CURVEBS_CHUNK_SIZE) + peers := config.GetBsFlagString(cCmd.Cmd, config.CURVEBS_PEERS_ADDRESS) + + var offset uint32 = 0 + peersAddress := strings.Split(peers, ",") + for _, address := range peersAddress { + rpc := &GetChunkHashRpc{ + Request: &chunk.GetChunkHashRequest{ + LogicPoolId: &logicalpoolid, + CopysetId: ©setid, + ChunkId: &chunkid, + Offset: &offset, + Length: &chunksize, + }, + } + rpc.Info = basecmd.NewRpc([]string{address}, timeout, retrytimes, "GetChunkHash") + cCmd.Rpc = append(cCmd.Rpc, rpc) + } + return nil +} + +func (cCmd *GetChunkHashCommand) RunCommand(cmd *cobra.Command, args []string) error { + var infos []*basecmd.Rpc + var funcs []basecmd.RpcFunc + for _, rpc := range cCmd.Rpc { + infos = append(infos, rpc.Info) + funcs = append(funcs, rpc) + } + results, errs := basecmd.GetRpcListResponse(infos, funcs) + if len(errs) == len(infos) { + mergeErr := cmderror.MergeCmdErrorExceptSuccess(errs) + return mergeErr.ToError() + } + + var preHash string + var curHash string + flag := true + for _, result := range results { + response, ok := result.(*chunk.GetChunkHashResponse) + if !ok { + return fmt.Errorf("response is nil") + } + if *response.Status != chunk.CHUNK_OP_STATUS_CHUNK_OP_STATUS_SUCCESS { + cCmd.result = false + cCmd.explain += chunk.CHUNK_OP_STATUS_name[int32(*response.Status)] + break + } + curHash = *response.Hash + if flag { + flag = false + preHash = curHash + continue + } + if preHash != curHash { + cCmd.result = false + cCmd.explain += "chunk hash inconsistent" + break + } + } + return nil +} + +func (cCmd *GetChunkHashCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&cCmd.FinalCurveCmd, cCmd) +} + +func (cCmd *GetChunkHashCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&cCmd.FinalCurveCmd) +} + +func (cCmd *GetChunkHashCommand) AddFlags() { + config.AddBsMdsFlagOption(cCmd.Cmd) + config.AddRpcRetryTimesFlag(cCmd.Cmd) + config.AddRpcTimeoutFlag(cCmd.Cmd) + + config.AddBsCopysetIdRequiredFlag(cCmd.Cmd) + config.AddBsLogicalPoolIdRequiredFlag(cCmd.Cmd) + config.AddBsPeersAddressFlag(cCmd.Cmd) + config.AddBsChunkIdRequiredFlag(cCmd.Cmd) + config.AddBsChunkSizeRequiredFlag(cCmd.Cmd) +} + +func GetChunkHash(caller *cobra.Command) (bool, string, *cmderror.CmdError) { + cCmd := NewGetChunkHashCommand() + config.AlignFlagsValue(caller, cCmd.Cmd, []string{ + config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, + config.CURVEBS_LOGIC_POOL_ID, config.CURVEBS_PEERS_ADDRESS, config.CURVEBS_CHUNK_ID, + config.CURVEBS_CHUNK_SIZE, config.CURVEBS_COPYSET_ID, + }) + cCmd.Cmd.SilenceErrors = true + cCmd.Cmd.SilenceUsage = true + cCmd.Cmd.SetArgs([]string{"--format", config.FORMAT_NOOUT}) + err := cCmd.Cmd.Execute() + if err != nil { + retErr := cmderror.ErrBsGetChunkHash() + retErr.Format(err.Error()) + return false, "", retErr + } + return cCmd.result, cCmd.explain, nil +} diff --git a/tools-v2/pkg/cli/command/curvebs/query/seginfo/seginfo.go b/tools-v2/pkg/cli/command/curvebs/query/seginfo/seginfo.go index 30b9da3653..2a1b672178 100644 --- a/tools-v2/pkg/cli/command/curvebs/query/seginfo/seginfo.go +++ b/tools-v2/pkg/cli/command/curvebs/query/seginfo/seginfo.go @@ -150,3 +150,24 @@ TaverSegment: func (sCmd *SeginfoCommand) ResultPlainOutput() error { return output.FinalCmdOutputPlain(&sCmd.FinalCurveCmd) } + + +//add for check file consistency (by victorseptember) +func GetSegmentInfo(caller *cobra.Command) ([]*nameserver2.PageFileSegment, *cmderror.CmdError) { + getCmd := NewQuerySeginfoCommand() + config.AlignFlagsValue(caller, getCmd.Cmd, []string{ + config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, + config.CURVEBS_PATH, + }) + getCmd.Cmd.SilenceErrors = true + getCmd.Cmd.SilenceUsage = true + getCmd.Cmd.SetArgs([]string{"--format", config.FORMAT_NOOUT}) + err := getCmd.Cmd.Execute() + if err != nil { + retErr := cmderror.ErrBsGetSegmentInfo() + retErr.Format(err.Error()) + return nil, retErr + } + result := getCmd.Result.([]*nameserver2.PageFileSegment) + return result, cmderror.Success() +} \ No newline at end of file diff --git a/tools-v2/pkg/cli/command/curvebs/status/copyset/agent.go b/tools-v2/pkg/cli/command/curvebs/status/copyset/agent.go index 8f3fe0b2ab..2a95901659 100644 --- a/tools-v2/pkg/cli/command/curvebs/status/copyset/agent.go +++ b/tools-v2/pkg/cli/command/curvebs/status/copyset/agent.go @@ -564,3 +564,90 @@ func MaxUint64(first, second uint64) uint64 { } return first } + +//check file consistency +func CheckCopysetsInChunkServers(address []string, addr2Id map[string]uint32, cs *Copyset, + copysetKeysSet set.Set[uint64], cmd *cobra.Command) (string, string, error) { + healthyStatus := cobrautil.HEALTH_OK + explain := "" + status, err := GetCopysetRaftStatus(address, cmd) + if err != nil { + return "", explain, err + } + for k, v := range status { + cs.updateChunkServerCopysets(k, v) + } + + for k, v := range status { + copysetsList := make([]map[string]string, 0) + for _, copysetStatusMap := range v { + key, err2 := strconv.ParseUint(copysetStatusMap[RAFT_STATUS_KEY_GROUPID], 10, 64) + if err2 != nil { + return "", explain, fmt.Errorf(COPYSET_CHECK_PARSE_ERROR) + } + if copysetKeysSet.Contains(key) { + copysetsList = append(copysetsList, copysetStatusMap) + } + } + cs.checkCopysetsOnChunkServer(k, copysetsList, addr2Id, cmd) + } + if _, ok := cs.copysetStat[int32(cobrautil.COPYSET_ERROR)]; ok && + cs.copysetStat[int32(cobrautil.COPYSET_ERROR)].Cardinality() > 0 { + healthyStatus = cobrautil.HEALTH_ERROR + explain = getErrorCopysetsInfo(cs) + } else if _, ok := cs.copysetStat[int32(cobrautil.COPYSET_WARN)]; ok && + cs.copysetStat[int32(cobrautil.COPYSET_WARN)].Cardinality() > 0 { + healthyStatus = cobrautil.HEALTH_WARN + explain = getWarnCopysetsInfo(cs) + } else { + healthyStatus = cobrautil.HEALTH_OK + explain = "-" + } + + return cobrautil.CopysetHealthStatus_Str[int32(healthyStatus)], explain, nil +} + +func getErrorCopysetsInfo(cs *Copyset) string { + message := "" + if _, ok := cs.copyset[COPYSET_CHECK_NO_LEADER]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_NO_LEADER].ToSlice()) { + message += fmt.Sprintf("copyset %s no leader peer.\n", key) + } + } + if _, ok := cs.copyset[COPYSET_CHECK_MAJORITY_PEER_OFFLINE]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_MAJORITY_PEER_OFFLINE].ToSlice()) { + message += fmt.Sprintf("copyset %s majority peer offline.\n", key) + } + } + if _, ok := cs.copyset[COPYSET_CHECK_INCONSISTENT]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_INCONSISTENT].ToSlice()) { + message += fmt.Sprintf("copyset %s check inconsistent.\n", key) + } + } + return message +} + +func getWarnCopysetsInfo(cs *Copyset) string { + message := "" + if _, ok := cs.copyset[COPYSET_CHECK_PEERS_NO_SUFFICIENT]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_PEERS_NO_SUFFICIENT].ToSlice()) { + message += fmt.Sprintf("copyset %s peers no sufficient.\n", key) + } + } + if _, ok := cs.copyset[COPYSET_CHECK_LOG_INDEX_TOO_BIG]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_LOG_INDEX_TOO_BIG].ToSlice()) { + message += fmt.Sprintf("copyset %s log index gap too big.\n", key) + } + } + if _, ok := cs.copyset[COPYSET_CHECK_INSTALLING_SNAPSHOT]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_INSTALLING_SNAPSHOT].ToSlice()) { + message += fmt.Sprintf("copyset %s installing snapshot.\n", key) + } + } + if _, ok := cs.copyset[COPYSET_CHECK_MINORITY_PEER_OFFLINE]; ok { + for _, key := range(cs.copyset[COPYSET_CHECK_MINORITY_PEER_OFFLINE].ToSlice()) { + message += fmt.Sprintf("copyset %s minority peers offline.\n", key) + } + } + return message +} \ No newline at end of file diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index 6b1da40887..08b80dd179 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -144,6 +144,11 @@ const ( VIPER_CURVEBS_TASKID = "curvebs.taskid" CURVEBS_FAILED = "failed" VIPER_CURVEBS_FAILED = "curvebs.failed" + CURVEBS_CHUNK_SIZE = "chunksize" + VIPER_CURVEBS_CHUNK_SIZE = "curvebs.chunksize" + CURVEBS_CHECK_HASH = "checkhash" + VIPER_CURVEBS_CHECK_HASH = "curvebs.checkhash" + CURVEBS_DEFAULT_CHECK_HASH = false ) var ( @@ -198,6 +203,8 @@ var ( CURVEBS_DEST: VIPER_CURVEBS_DEST, CURVEBS_TASKID: VIPER_CURVEBS_TASKID, CURVEBS_FAILED: VIPER_CURVEBS_FAILED, + CURVEBS_CHUNK_SIZE: VIPER_CURVEBS_CHUNK_SIZE, + CURVEBS_CHECK_HASH: VIPER_CURVEBS_CHECK_HASH, } BSFLAG2DEFAULT = map[string]interface{}{ @@ -221,6 +228,7 @@ var ( CURVEBS_ALL: CURVEBS_DEFAULT_ALL, CURVEBS_LOGIC_POOL_ID: CURVEBS_DEFAULT_LOGIC_POOL_ID, CURVEBS_COPYSET_ID: CURVEBS_DEFAULT_COPYSET_ID, + CURVEBS_CHECK_HASH: CURVEBS_DEFAULT_CHECK_HASH, } ) @@ -558,6 +566,10 @@ func AddBsPeersConfFlag(cmd *cobra.Command) { AddBsStringSliceRequiredFlag(cmd, CURVEBS_PEERS_ADDRESS, "peers info.") } +func AddBsPeersAddressFlag(cmd *cobra.Command) { + AddBsStringRequiredFlag(cmd, CURVEBS_PEERS_ADDRESS, "peers address.") +} + func AddBsForceDeleteOptionFlag(cmd *cobra.Command) { AddBsBoolOptionFlag(cmd, CURVEBS_FORCE, "whether to force delete the file") } @@ -614,6 +626,18 @@ func AddBsChunkIdSliceRequiredFlag(cmd *cobra.Command) { AddBsStringSliceRequiredFlag(cmd, CURVEBS_CHUNK_ID, "chunk ids") } +func AddBsChunkIdRequiredFlag(cmd *cobra.Command) { + AddBsUint64RequiredFlag(cmd, CURVEBS_CHUNK_ID, "chunk id") +} + +func AddBsChunkSizeRequiredFlag(cmd *cobra.Command) { + AddBsUint32RequiredFlag(cmd, CURVEBS_CHUNK_SIZE, "chunk size") +} + +func AddBsCheckHashOptionFlag(cmd *cobra.Command) { + AddBsBoolOptionFlag(cmd, CURVEBS_CHECK_HASH, "whether to check chunk hash(take longer time)") +} + func AddBsChunkServerAddressSliceRequiredFlag(cmd *cobra.Command) { AddBsStringSliceRequiredFlag(cmd, CURVEBS_CHUNKSERVER_ADDRESS, "chunk server address") }