[#947] cli: Allow to specify evacuation scope

It may be required to evacuate only objects or only tree or all, so
now it spossible to specify.

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
Dmitrii Stepanov 2024-02-05 16:33:09 +03:00
parent a6eb66bf9c
commit b3f3505ada
7 changed files with 67 additions and 0 deletions

View file

@ -19,6 +19,11 @@ import (
const ( const (
awaitFlag = "await" awaitFlag = "await"
noProgressFlag = "no-progress" noProgressFlag = "no-progress"
scopeFlag = "scope"
scopeAll = "all"
scopeObjects = "objects"
scopeTrees = "trees"
) )
var evacuationShardCmd = &cobra.Command{ var evacuationShardCmd = &cobra.Command{
@ -57,6 +62,7 @@ func startEvacuateShard(cmd *cobra.Command, _ []string) {
Body: &control.StartShardEvacuationRequest_Body{ Body: &control.StartShardEvacuationRequest_Body{
Shard_ID: getShardIDList(cmd), Shard_ID: getShardIDList(cmd),
IgnoreErrors: ignoreErrors, IgnoreErrors: ignoreErrors,
Scope: getEvacuationScope(cmd),
}, },
} }
@ -82,6 +88,22 @@ func startEvacuateShard(cmd *cobra.Command, _ []string) {
} }
} }
func getEvacuationScope(cmd *cobra.Command) uint32 {
rawScope, err := cmd.Flags().GetString(scopeFlag)
commonCmd.ExitOnErr(cmd, "Invalid scope value: %w", err)
switch rawScope {
case scopeAll:
return uint32(control.StartShardEvacuationRequest_Body_OBJECTS) | uint32(control.StartShardEvacuationRequest_Body_TREES)
case scopeObjects:
return uint32(control.StartShardEvacuationRequest_Body_OBJECTS)
case scopeTrees:
return uint32(control.StartShardEvacuationRequest_Body_TREES)
default:
commonCmd.ExitOnErr(cmd, "Invalid scope value: %w", fmt.Errorf("unknown scope %s", rawScope))
}
return uint32(control.StartShardEvacuationRequest_Body_NONE)
}
func getEvacuateShardStatus(cmd *cobra.Command, _ []string) { func getEvacuateShardStatus(cmd *cobra.Command, _ []string) {
pk := key.Get(cmd) pk := key.Get(cmd)
req := &control.GetShardEvacuationStatusRequest{ req := &control.GetShardEvacuationStatusRequest{
@ -309,6 +331,7 @@ func initControlStartEvacuationShardCmd() {
flags.StringSlice(shardIDFlag, nil, "List of shard IDs in base58 encoding") flags.StringSlice(shardIDFlag, nil, "List of shard IDs in base58 encoding")
flags.Bool(shardAllFlag, false, "Process all shards") flags.Bool(shardAllFlag, false, "Process all shards")
flags.Bool(ignoreErrorsFlag, true, "Skip invalid/unreadable objects") flags.Bool(ignoreErrorsFlag, true, "Skip invalid/unreadable objects")
flags.String(scopeFlag, scopeAll, fmt.Sprintf("Evacuation scope; possible values: %s, %s, %s", scopeTrees, scopeObjects, scopeAll))
flags.Bool(awaitFlag, false, "Block execution until evacuation is completed") flags.Bool(awaitFlag, false, "Block execution until evacuation is completed")
flags.Bool(noProgressFlag, false, fmt.Sprintf("Print progress if %s provided", awaitFlag)) flags.Bool(noProgressFlag, false, fmt.Sprintf("Print progress if %s provided", awaitFlag))

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"strings"
"sync/atomic" "sync/atomic"
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
@ -28,12 +29,40 @@ var (
evacuationOperationLogField = zap.String("operation", "evacuation") evacuationOperationLogField = zap.String("operation", "evacuation")
) )
// EvacuateScope is an evacuation scope. Keep in sync with pkg/services/control/service.proto.
type EvacuateScope uint32
var (
EvacuateScopeObjects EvacuateScope = 1
EvacuateScopeTrees EvacuateScope = 2
)
func (s EvacuateScope) String() string {
var sb strings.Builder
first := true
if s&EvacuateScopeObjects == EvacuateScopeObjects {
if !first {
sb.WriteString(";")
}
sb.WriteString("objects")
first = false
}
if s&EvacuateScopeTrees == EvacuateScopeTrees {
if !first {
sb.WriteString(";")
}
sb.WriteString("trees")
}
return sb.String()
}
// EvacuateShardPrm represents parameters for the EvacuateShard operation. // EvacuateShardPrm represents parameters for the EvacuateShard operation.
type EvacuateShardPrm struct { type EvacuateShardPrm struct {
ShardID []*shard.ID ShardID []*shard.ID
Handler func(context.Context, oid.Address, *objectSDK.Object) error Handler func(context.Context, oid.Address, *objectSDK.Object) error
IgnoreErrors bool IgnoreErrors bool
Async bool Async bool
Scope EvacuateScope
} }
// EvacuateShardRes represents result of the EvacuateShard operation. // EvacuateShardRes represents result of the EvacuateShard operation.
@ -135,6 +164,7 @@ func (e *StorageEngine) Evacuate(ctx context.Context, prm EvacuateShardPrm) (*Ev
attribute.StringSlice("shardIDs", shardIDs), attribute.StringSlice("shardIDs", shardIDs),
attribute.Bool("async", prm.Async), attribute.Bool("async", prm.Async),
attribute.Bool("ignoreErrors", prm.IgnoreErrors), attribute.Bool("ignoreErrors", prm.IgnoreErrors),
attribute.Stringer("scope", prm.Scope),
)) ))
defer span.End() defer span.End()

View file

@ -29,6 +29,7 @@ func (s *Server) EvacuateShard(ctx context.Context, req *control.EvacuateShardRe
ShardID: s.getShardIDList(req.GetBody().GetShard_ID()), ShardID: s.getShardIDList(req.GetBody().GetShard_ID()),
IgnoreErrors: req.GetBody().GetIgnoreErrors(), IgnoreErrors: req.GetBody().GetIgnoreErrors(),
Handler: s.replicate, Handler: s.replicate,
Scope: engine.EvacuateScopeObjects,
} }
res, err := s.s.Evacuate(ctx, prm) res, err := s.s.Evacuate(ctx, prm)

View file

@ -17,11 +17,16 @@ func (s *Server) StartShardEvacuation(ctx context.Context, req *control.StartSha
return nil, status.Error(codes.PermissionDenied, err.Error()) return nil, status.Error(codes.PermissionDenied, err.Error())
} }
if req.GetBody().GetScope() == uint32(control.StartShardEvacuationRequest_Body_NONE) {
return nil, status.Error(codes.InvalidArgument, "no evacuation scope")
}
prm := engine.EvacuateShardPrm{ prm := engine.EvacuateShardPrm{
ShardID: s.getShardIDList(req.GetBody().GetShard_ID()), ShardID: s.getShardIDList(req.GetBody().GetShard_ID()),
IgnoreErrors: req.GetBody().GetIgnoreErrors(), IgnoreErrors: req.GetBody().GetIgnoreErrors(),
Handler: s.replicate, Handler: s.replicate,
Async: true, Async: true,
Scope: engine.EvacuateScope(req.GetBody().GetScope()),
} }
_, err = s.s.Evacuate(ctx, prm) _, err = s.s.Evacuate(ctx, prm)

Binary file not shown.

View file

@ -336,10 +336,18 @@ message DoctorResponse {
message StartShardEvacuationRequest { message StartShardEvacuationRequest {
// Request body structure. // Request body structure.
message Body { message Body {
enum Scope {
NONE = 0;
OBJECTS = 1;
TREES = 2;
}
// IDs of the shards. // IDs of the shards.
repeated bytes shard_ID = 1; repeated bytes shard_ID = 1;
// Flag indicating whether object read errors should be ignored. // Flag indicating whether object read errors should be ignored.
bool ignore_errors = 2; bool ignore_errors = 2;
// Evacuation scope.
uint32 scope = 3;
} }
Body body = 1; Body body = 1;

Binary file not shown.