From bfdd68dcb37a13d3caaab2d36e81b383d45920db Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 16 May 2022 19:31:50 +0300 Subject: [PATCH] [#1333] services/control: Allow to synchronize local trees Do not check that a node indeed belongs to the container, because the synchronization will fail in this case anyway. Signed-off-by: Evgenii Stratonikov --- cmd/neofs-node/config.go | 3 ++ cmd/neofs-node/control.go | 1 + cmd/neofs-node/tree.go | 8 +-- pkg/services/control/convert.go | 18 +++++++ pkg/services/control/rpc.go | 14 +++++ pkg/services/control/server/server.go | 12 ++++- .../control/server/syncronize_tree.go | 48 ++++++++++++++++++ pkg/services/control/service.go | 14 +++++ pkg/services/control/service.pb.go | Bin 89362 -> 100536 bytes pkg/services/control/service.proto | 33 ++++++++++++ pkg/services/control/service_grpc.pb.go | Bin 14980 -> 16663 bytes pkg/services/control/service_neofs.pb.go | Bin 41905 -> 47260 bytes pkg/services/control/service_test.go | 18 +++++++ 13 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 pkg/services/control/server/syncronize_tree.go diff --git a/cmd/neofs-node/config.go b/cmd/neofs-node/config.go index d273ea7ec..7a725f080 100644 --- a/cmd/neofs-node/config.go +++ b/cmd/neofs-node/config.go @@ -40,6 +40,7 @@ import ( tsourse "github.com/nspcc-dev/neofs-node/pkg/services/object_manager/tombstone/source" trustcontroller "github.com/nspcc-dev/neofs-node/pkg/services/reputation/local/controller" truststorage "github.com/nspcc-dev/neofs-node/pkg/services/reputation/local/storage" + "github.com/nspcc-dev/neofs-node/pkg/services/tree" "github.com/nspcc-dev/neofs-node/pkg/services/util/response" "github.com/nspcc-dev/neofs-node/pkg/util" "github.com/nspcc-dev/neofs-node/pkg/util/logger" @@ -111,6 +112,8 @@ type cfg struct { cfgControlService cfgControlService + treeService *tree.Service + healthStatus *atomic.Int32 closers []func() diff --git a/cmd/neofs-node/control.go b/cmd/neofs-node/control.go index 5e6c76204..439050a0e 100644 --- a/cmd/neofs-node/control.go +++ b/cmd/neofs-node/control.go @@ -43,6 +43,7 @@ func initControlService(c *cfg) { return err }), controlSvc.WithLocalStorage(c.cfgObject.cfgLocalStorage.localStorage), + controlSvc.WithTreeService(c.treeService), ) lis, err := net.Listen("tcp", endpoint) diff --git a/cmd/neofs-node/tree.go b/cmd/neofs-node/tree.go index 95987402b..4be5ac093 100644 --- a/cmd/neofs-node/tree.go +++ b/cmd/neofs-node/tree.go @@ -7,7 +7,7 @@ import ( ) func initTreeService(c *cfg) { - treeSvc := tree.New( + c.treeService = tree.New( tree.WithContainerSource(c.cfgObject.cnrSource), tree.WithNetmapSource(c.netMapSource), tree.WithPrivateKey(&c.key.PrivateKey), @@ -15,12 +15,12 @@ func initTreeService(c *cfg) { tree.WithStorage(c.cfgObject.cfgLocalStorage.localStorage)) for _, srv := range c.cfgGRPC.servers { - tree.RegisterTreeServiceServer(srv, treeSvc) + tree.RegisterTreeServiceServer(srv, c.treeService) } c.workers = append(c.workers, newWorkerFromFunc(func(ctx context.Context) { - treeSvc.Start(ctx) + c.treeService.Start(ctx) })) - c.onShutdown(treeSvc.Shutdown) + c.onShutdown(c.treeService.Shutdown) } diff --git a/pkg/services/control/convert.go b/pkg/services/control/convert.go index b8a8a616b..a4d0bced6 100644 --- a/pkg/services/control/convert.go +++ b/pkg/services/control/convert.go @@ -166,3 +166,21 @@ func (w *restoreShardResponseWrapper) FromGRPCMessage(m grpc.Message) error { w.RestoreShardResponse = r return nil } + +type synchronizeTreeResponseWrapper struct { + *SynchronizeTreeResponse +} + +func (w *synchronizeTreeResponseWrapper) ToGRPCMessage() grpc.Message { + return w.SynchronizeTreeResponse +} + +func (w *synchronizeTreeResponseWrapper) FromGRPCMessage(m grpc.Message) error { + r, ok := m.(*SynchronizeTreeResponse) + if !ok { + return message.NewUnexpectedMessageType(m, (*SynchronizeTreeResponse)(nil)) + } + + w.SynchronizeTreeResponse = r + return nil +} diff --git a/pkg/services/control/rpc.go b/pkg/services/control/rpc.go index 4c23f503c..13751e692 100644 --- a/pkg/services/control/rpc.go +++ b/pkg/services/control/rpc.go @@ -16,6 +16,7 @@ const ( rpcSetShardMode = "SetShardMode" rpcDumpShard = "DumpShard" rpcRestoreShard = "RestoreShard" + rpcSynchronizeTree = "SynchronizeTree" ) // HealthCheck executes ControlService.HealthCheck RPC. @@ -172,3 +173,16 @@ func RestoreShard(cli *client.Client, req *RestoreShardRequest, opts ...client.C return wResp.RestoreShardResponse, nil } + +// SynchronizeTree executes ControlService.SynchronizeTree RPC. +func SynchronizeTree(cli *client.Client, req *SynchronizeTreeRequest, opts ...client.CallOption) (*SynchronizeTreeResponse, error) { + wResp := &synchronizeTreeResponseWrapper{new(SynchronizeTreeResponse)} + wReq := &requestWrapper{m: req} + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceName, rpcSynchronizeTree), wReq, wResp, opts...) + if err != nil { + return nil, err + } + + return wResp.SynchronizeTreeResponse, nil +} diff --git a/pkg/services/control/server/server.go b/pkg/services/control/server/server.go index 562e5dc27..f1b0e5736 100644 --- a/pkg/services/control/server/server.go +++ b/pkg/services/control/server/server.go @@ -3,9 +3,8 @@ package control import ( "crypto/ecdsa" - "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" - "github.com/nspcc-dev/neofs-node/pkg/core/netmap" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" "github.com/nspcc-dev/neofs-node/pkg/services/control" ) @@ -52,6 +51,8 @@ type cfg struct { delObjHandler DeletedObjectHandler + treeService TreeService + s *engine.StorageEngine } @@ -125,3 +126,10 @@ func WithLocalStorage(engine *engine.StorageEngine) Option { c.s = engine } } + +// WithTreeService returns an option to set tree service. +func WithTreeService(s TreeService) Option { + return func(c *cfg) { + c.treeService = s + } +} diff --git a/pkg/services/control/server/syncronize_tree.go b/pkg/services/control/server/syncronize_tree.go new file mode 100644 index 000000000..b4e91071e --- /dev/null +++ b/pkg/services/control/server/syncronize_tree.go @@ -0,0 +1,48 @@ +package control + +import ( + "context" + + "github.com/nspcc-dev/neofs-node/pkg/services/control" + cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// TreeService represents a tree service instance. +type TreeService interface { + Synchronize(ctx context.Context, cnr cid.ID, treeID string) error +} + +func (s *Server) SynchronizeTree(ctx context.Context, req *control.SynchronizeTreeRequest) (*control.SynchronizeTreeResponse, error) { + err := s.isValidRequest(req) + if err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + + if s.treeService == nil { + return nil, status.Error(codes.Internal, "tree service is disabled") + } + + b := req.GetBody() + + var cnr cid.ID + if err := cnr.Decode(b.GetContainerId()); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + err = s.treeService.Synchronize(ctx, cnr, b.GetTreeId()) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + resp := new(control.SynchronizeTreeResponse) + resp.SetBody(new(control.SynchronizeTreeResponse_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.go b/pkg/services/control/service.go index f120b388e..2cf9ee774 100644 --- a/pkg/services/control/service.go +++ b/pkg/services/control/service.go @@ -200,3 +200,17 @@ func (x *RestoreShardResponse) SetBody(v *RestoreShardResponse_Body) { x.Body = v } } + +// SetBody sets list shards request body. +func (x *SynchronizeTreeRequest) SetBody(v *SynchronizeTreeRequest_Body) { + if x != nil { + x.Body = v + } +} + +// SetBody sets list shards response body. +func (x *SynchronizeTreeResponse) SetBody(v *SynchronizeTreeResponse_Body) { + if x != nil { + x.Body = v + } +} diff --git a/pkg/services/control/service.pb.go b/pkg/services/control/service.pb.go index 435cd25f3c17034fd84863f3af1c16b230378b48..4ad323c075fe13b25b1fad8127fa8fce8c6a852c 100644 GIT binary patch delta 6209 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 NPr<#TcrJVd{{fDB9drNy delta 2977 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 M4c397J@9Y%Ke3(TX8-^I diff --git a/pkg/services/control/service.proto b/pkg/services/control/service.proto index 3446e262e..5f90399d8 100644 --- a/pkg/services/control/service.proto +++ b/pkg/services/control/service.proto @@ -31,6 +31,9 @@ service ControlService { // Restore objects from dump. rpc RestoreShard (RestoreShardRequest) returns (RestoreShardResponse); + + // Synchronizes all log operations for the specified tree. + rpc SynchronizeTree (SynchronizeTreeRequest) returns (SynchronizeTreeResponse); } // Health check request. @@ -279,3 +282,33 @@ message RestoreShardResponse { // Body signature. Signature signature = 2; } + +// SynchronizeTree request. +message SynchronizeTreeRequest { + // Request body structure. + message Body { + bytes container_id = 1; + string tree_id = 2; + // Starting height for the synchronization. Can be omitted. + uint64 height = 3; + } + + // Body of restore shard request message. + Body body = 1; + + // Body signature. + Signature signature = 2; +} + +// SynchronizeTree response. +message SynchronizeTreeResponse { + // Response body structure. + message Body { + } + + // Body of restore shard response message. + Body body = 1; + + // Body signature. + Signature signature = 2; +} diff --git a/pkg/services/control/service_grpc.pb.go b/pkg/services/control/service_grpc.pb.go index 5c088311a3e2e2aa92a6bc3a2cb19575515fe53e..bee17aee507a10d8da54944a756470b9b1725a59 100644 GIT binary patch delta 634 zcmZoEo!-Q_A%er3Q(s>pxH2y}qbNTwvnsV%Au%UMAtygwA-^ECD6u3nKd)FJEx$;i zBqLR!xF9t-Gc7YUMWLi9HC2y`6G>x8QR?K2Y%+WZqktl*lO1?f_)%4*Zg%Im%{6&G zw*oJUS{%ChP<2lZkQJT0kB=MO(8+r^Z7{?FxcxUP34dnsp`s^KCnt&vYoaP zG_|-yQ$a%uO=dHTL^S*4y|S7ZjsqH_fukQPbK=*=1a!G}bLQ!g=9)|BGH!9m~zF`{1GFjGA1l_2I7D^b7 Ikh4ky0DV&JeEVgz_rf70;76Vl)Xxl0j6y=xX>xFvem6(|X1I09qbrdS}JW?~$GfFla zDo`Y!H(sf8?EsZqR1IdNC#p!9b}g z7=n`xBJZLrocz!zAKl~UIgjz7x^}WavDoJL!sU#-D4qZcpGMQXxxYgk!{W{ByQX3Y VPM&XlA5HV*i2?Z-4!o~n2LSkzrqBQY delta 9 RcmbR9k!j;`rVSex0{|I81r7iJ diff --git a/pkg/services/control/service_test.go b/pkg/services/control/service_test.go index 8a3167543..8dbfffa4d 100644 --- a/pkg/services/control/service_test.go +++ b/pkg/services/control/service_test.go @@ -161,3 +161,21 @@ func equalSetShardModeRequestBodies(b1, b2 *control.SetShardModeRequest_Body) bo return true } + +func TestSynchronizeTreeRequest_Body_StableMarshal(t *testing.T) { + testStableMarshal(t, + &control.SynchronizeTreeRequest_Body{ + ContainerId: []byte{1, 2, 3, 4, 5, 6, 7}, + TreeId: "someID", + Height: 42, + }, + new(control.SynchronizeTreeRequest_Body), + func(m1, m2 protoMessage) bool { + b1 := m1.(*control.SynchronizeTreeRequest_Body) + b2 := m2.(*control.SynchronizeTreeRequest_Body) + return bytes.Equal(b1.GetContainerId(), b2.GetContainerId()) && + b1.GetTreeId() == b2.GetTreeId() && + b1.GetHeight() == b2.GetHeight() + }, + ) +}