diff --git a/pkg/local_object_storage/engine/evacuate.go b/pkg/local_object_storage/engine/evacuate.go index 45600fe66..81fe47e65 100644 --- a/pkg/local_object_storage/engine/evacuate.go +++ b/pkg/local_object_storage/engine/evacuate.go @@ -733,3 +733,13 @@ func (e *StorageEngine) EnqueRunningEvacuationStop(ctx context.Context) error { return e.evacuateLimiter.CancelIfRunning() } + +func (e *StorageEngine) ResetEvacuationStatus(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + return e.evacuateLimiter.ResetEvacuationStatus() +} diff --git a/pkg/local_object_storage/engine/evacuate_limiter.go b/pkg/local_object_storage/engine/evacuate_limiter.go index 63960e238..1e6b9ccb1 100644 --- a/pkg/local_object_storage/engine/evacuate_limiter.go +++ b/pkg/local_object_storage/engine/evacuate_limiter.go @@ -204,3 +204,18 @@ func (l *evacuationLimiter) CancelIfRunning() error { l.cancel() return nil } + +func (l *evacuationLimiter) ResetEvacuationStatus() error { + l.guard.Lock() + defer l.guard.Unlock() + + if l.state.processState == EvacuateProcessStateRunning { + return logicerr.New("there is running evacuation task") + } + + l.state = EvacuationState{} + l.eg = nil + l.cancel = nil + + return nil +} diff --git a/pkg/local_object_storage/engine/evacuate_test.go b/pkg/local_object_storage/engine/evacuate_test.go index 32582cd2a..e8d9a449f 100644 --- a/pkg/local_object_storage/engine/evacuate_test.go +++ b/pkg/local_object_storage/engine/evacuate_test.go @@ -386,6 +386,8 @@ func TestEvacuateObjectsAsync(t *testing.T) { require.ElementsMatch(t, expectedShardIDs, st.ShardIDs(), "invalid running shard ids") require.Equal(t, "", st.ErrorMessage(), "invalid init error message") + require.Error(t, e.ResetEvacuationStatus(context.Background())) + close(blocker) require.Eventually(t, func() bool { @@ -401,6 +403,16 @@ func TestEvacuateObjectsAsync(t *testing.T) { require.Equal(t, "", st.ErrorMessage(), "invalid final error message") require.NoError(t, eg.Wait()) + + require.NoError(t, e.ResetEvacuationStatus(context.Background())) + st, err = e.GetEvacuationState(context.Background()) + require.NoError(t, err, "get state after reset failed") + require.Equal(t, EvacuateProcessStateUndefined, st.ProcessingStatus(), "invalid state after reset") + require.Equal(t, uint64(0), st.ObjectsEvacuated(), "invalid count after reset") + require.Nil(t, st.StartedAt(), "invalid started at after reset") + require.Nil(t, st.FinishedAt(), "invalid finished at after reset") + require.ElementsMatch(t, []string{}, st.ShardIDs(), "invalid shard ids after reset") + require.Equal(t, "", st.ErrorMessage(), "invalid error message after reset") } func TestEvacuateTreesLocal(t *testing.T) { diff --git a/pkg/services/control/server/evacuate_async.go b/pkg/services/control/server/evacuate_async.go index cd7e8a2c7..42ae2635b 100644 --- a/pkg/services/control/server/evacuate_async.go +++ b/pkg/services/control/server/evacuate_async.go @@ -102,3 +102,29 @@ func (s *Server) StopShardEvacuation(ctx context.Context, req *control.StopShard } return resp, nil } + +func (s *Server) ResetShardEvacuationStatus(ctx context.Context, req *control.ResetShardEvacuationStatusRequest) (*control.ResetShardEvacuationStatusResponse, error) { + err := s.isValidRequest(req) + if err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + + err = s.s.ResetEvacuationStatus(ctx) + if err != nil { + var logicalErr logicerr.Logical + if errors.As(err, &logicalErr) { + return nil, status.Error(codes.Aborted, err.Error()) + } + return nil, status.Error(codes.Internal, err.Error()) + } + + resp := &control.ResetShardEvacuationStatusResponse{ + Body: &control.ResetShardEvacuationStatusResponse_Body{}, + } + + err = SignMessage(s.key, resp) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + return resp, nil +} diff --git a/pkg/services/control/service.pb.go b/pkg/services/control/service.pb.go index 261065b58..586619767 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 1377965e6..8501e952f 100644 --- a/pkg/services/control/service.proto +++ b/pkg/services/control/service.proto @@ -36,6 +36,9 @@ service ControlService { // GetShardEvacuationStatus returns evacuation status. rpc GetShardEvacuationStatus (GetShardEvacuationStatusRequest) returns (GetShardEvacuationStatusResponse); + // ResetShardEvacuationStatus resets evacuation status if there is no running evacuation process. + rpc ResetShardEvacuationStatus (ResetShardEvacuationStatusRequest) returns (ResetShardEvacuationStatusResponse); + // StopShardEvacuation stops moving all data from one shard to the others. rpc StopShardEvacuation (StopShardEvacuationRequest) returns (StopShardEvacuationResponse); @@ -426,6 +429,22 @@ message GetShardEvacuationStatusResponse { Signature signature = 2; } +// ResetShardEvacuationStatus request. +message ResetShardEvacuationStatusRequest { + message Body {} + + Body body = 1; + Signature signature = 2; +} + +// ResetShardEvacuationStatus response. +message ResetShardEvacuationStatusResponse { + message Body {} + + Body body = 1; + Signature signature = 2; +} + // StopShardEvacuation request. message StopShardEvacuationRequest { // Request body structure. diff --git a/pkg/services/control/service_frostfs.pb.go b/pkg/services/control/service_frostfs.pb.go index 56b2bd54c..b90749269 100644 Binary files a/pkg/services/control/service_frostfs.pb.go and b/pkg/services/control/service_frostfs.pb.go differ diff --git a/pkg/services/control/service_grpc.pb.go b/pkg/services/control/service_grpc.pb.go index 69029ccb3..ad33e330a 100644 Binary files a/pkg/services/control/service_grpc.pb.go and b/pkg/services/control/service_grpc.pb.go differ