diff --git a/cmd/neofs-cli/modules/control.go b/cmd/neofs-cli/modules/control.go index 6e424bb64..146f21b17 100644 --- a/cmd/neofs-cli/modules/control.go +++ b/cmd/neofs-cli/modules/control.go @@ -71,8 +71,9 @@ const ( netmapStatusOffline = "offline" netmapStatusMaintenance = "maintenance" - shardModeFlag = "mode" - shardIDFlag = "id" + shardModeFlag = "mode" + shardIDFlag = "id" + shardClearErrorsFlag = "clear-errors" shardModeReadOnly = "read-only" shardModeReadWrite = "read-write" @@ -127,6 +128,7 @@ func initControlSetShardModeCmd() { shardModeReadOnly, ), ) + flags.Bool(shardClearErrorsFlag, false, "Set shard error count to 0") } func initControlShardsListCmd() { @@ -510,6 +512,9 @@ func setShardMode(cmd *cobra.Command, _ []string) { body.SetMode(mode) body.SetShardID(rawID) + reset, _ := cmd.Flags().GetBool(shardClearErrorsFlag) + body.ClearErrorCounter(reset) + err = controlSvc.SignMessage(key, req) exitOnErr(cmd, errf("could not sign request: %w", err)) diff --git a/pkg/local_object_storage/engine/error_test.go b/pkg/local_object_storage/engine/error_test.go index 13d8a63f7..b968a3731 100644 --- a/pkg/local_object_storage/engine/error_test.go +++ b/pkg/local_object_storage/engine/error_test.go @@ -114,6 +114,12 @@ func TestErrorReporting(t *testing.T) { checkShardState(t, e, id[0], errThreshold+i, shard.ModeReadOnly) checkShardState(t, e, id[1], 0, shard.ModeReadWrite) } + + require.NoError(t, e.SetShardMode(id[0], shard.ModeReadWrite, false)) + checkShardState(t, e, id[0], errThreshold+1, shard.ModeReadWrite) + + require.NoError(t, e.SetShardMode(id[0], shard.ModeReadWrite, true)) + checkShardState(t, e, id[0], 0, shard.ModeReadWrite) }) } diff --git a/pkg/local_object_storage/engine/shards.go b/pkg/local_object_storage/engine/shards.go index d4c4fcde5..8fb4a1354 100644 --- a/pkg/local_object_storage/engine/shards.go +++ b/pkg/local_object_storage/engine/shards.go @@ -118,12 +118,15 @@ func (e *StorageEngine) iterateOverUnsortedShards(handler func(hashedShard) (sto // SetShardMode sets mode of the shard with provided identifier. // // Returns an error if shard mode was not set, or shard was not found in storage engine. -func (e *StorageEngine) SetShardMode(id *shard.ID, m shard.Mode) error { +func (e *StorageEngine) SetShardMode(id *shard.ID, m shard.Mode, resetErrorCounter bool) error { e.mtx.RLock() defer e.mtx.RUnlock() for shID, sh := range e.shards { if id.String() == shID { + if resetErrorCounter { + sh.errorCount.Store(0) + } return sh.SetMode(m) } } diff --git a/pkg/services/control/server/set_shard_mode.go b/pkg/services/control/server/set_shard_mode.go index 86e9c7dce..01edcfdbd 100644 --- a/pkg/services/control/server/set_shard_mode.go +++ b/pkg/services/control/server/set_shard_mode.go @@ -33,7 +33,7 @@ func (s *Server) SetShardMode(_ context.Context, req *control.SetShardModeReques return nil, status.Error(codes.Internal, fmt.Sprintf("unknown shard mode: %s", requestedMode)) } - err = s.s.SetShardMode(requestedShard, mode) + err = s.s.SetShardMode(requestedShard, mode, false) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/pkg/services/control/service.go b/pkg/services/control/service.go index d14604914..7f0b0d7aa 100644 --- a/pkg/services/control/service.go +++ b/pkg/services/control/service.go @@ -761,10 +761,16 @@ func (x *SetShardModeRequest_Body) SetMode(v ShardMode) { x.Mode = v } +// ClearErrorCounter sets flag signifying whether error counter for shard should be cleared. +func (x *SetShardModeRequest_Body) ClearErrorCounter(reset bool) { + x.ResetErrorCounter = reset +} + const ( _ = iota setShardModeReqBodyShardIDFNum setShardModeReqBodyModeFNum + setShardModeReqBodyResetCounterFNum ) // StableMarshal reads binary representation of set shard mode request body @@ -797,7 +803,14 @@ func (x *SetShardModeRequest_Body) StableMarshal(buf []byte) ([]byte, error) { offset += n - _, err = proto.EnumMarshal(setShardModeReqBodyModeFNum, buf[offset:], int32(x.Mode)) + n, err = proto.EnumMarshal(setShardModeReqBodyModeFNum, buf[offset:], int32(x.Mode)) + if err != nil { + return nil, err + } + + offset += n + + _, err = proto.BoolMarshal(setShardModeReqBodyResetCounterFNum, buf[offset:], x.ResetErrorCounter) if err != nil { return nil, err } @@ -818,6 +831,7 @@ func (x *SetShardModeRequest_Body) StableSize() int { size += proto.BytesSize(setShardModeReqBodyShardIDFNum, x.Shard_ID) size += proto.EnumSize(setShardModeReqBodyModeFNum, int32(x.Mode)) + size += proto.BoolSize(setShardModeReqBodyResetCounterFNum, x.ResetErrorCounter) return size } diff --git a/pkg/services/control/service.pb.go b/pkg/services/control/service.pb.go index b6d8e046c..87e8913a5 100644 Binary files a/pkg/services/control/service.pb.go and b/pkg/services/control/service.pb.go differ diff --git a/pkg/services/control/service.proto b/pkg/services/control/service.proto index c34b2cf7a..3446e262e 100644 --- a/pkg/services/control/service.proto +++ b/pkg/services/control/service.proto @@ -186,6 +186,9 @@ message SetShardModeRequest { // Mode that requested to be set. ShardMode mode = 2; + + // Flag signifying whether error counter should be set to 0. + bool resetErrorCounter = 3; } // Body of set shard mode request message.