From 398a28a8ddb643faaf2e21e340fcca3a4690fcc0 Mon Sep 17 00:00:00 2001 From: qkrorlqr Date: Sat, 28 Sep 2024 12:33:32 +0000 Subject: [PATCH 1/4] issue-1795: implemented Unsafe{Delete,Update,Get}Node to use it in private api for manual interventions - e.g. to clean up OrphanNodes --- cloud/filestore/libs/storage/api/tablet.h | 12 + .../filestore/libs/storage/tablet/helpers.cpp | 18 +- cloud/filestore/libs/storage/tablet/helpers.h | 10 +- .../tablet/tablet_actor_unsafe_node_ops.cpp | 272 ++++++++++++++++++ .../filestore/libs/storage/tablet/tablet_tx.h | 72 ++++- cloud/filestore/libs/storage/tablet/ya.make | 1 + .../filestore/private/api/protos/tablet.proto | 41 +++ 7 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp diff --git a/cloud/filestore/libs/storage/api/tablet.h b/cloud/filestore/libs/storage/api/tablet.h index 977878d77b..d94309e22a 100644 --- a/cloud/filestore/libs/storage/api/tablet.h +++ b/cloud/filestore/libs/storage/api/tablet.h @@ -32,6 +32,9 @@ namespace NCloud::NFileStore::NStorage { xxx(GetStorageConfig, __VA_ARGS__) \ xxx(GetNodeAttrBatch, __VA_ARGS__) \ xxx(WriteCompactionMap, __VA_ARGS__) \ + xxx(UnsafeDeleteNode, __VA_ARGS__) \ + xxx(UnsafeUpdateNode, __VA_ARGS__) \ + xxx(UnsafeGetNode, __VA_ARGS__) \ // FILESTORE_TABLET_REQUESTS //////////////////////////////////////////////////////////////////////////////// @@ -97,6 +100,15 @@ struct TEvIndexTablet EvWriteCompactionMapRequest = EvBegin + 33, EvWriteCompactionMapResponse, + EvUnsafeDeleteNodeRequest = EvBegin + 35, + EvUnsafeDeleteNodeResponse, + + EvUnsafeUpdateNodeRequest = EvBegin + 37, + EvUnsafeUpdateNodeResponse, + + EvUnsafeGetNodeRequest = EvBegin + 39, + EvUnsafeGetNodeResponse, + EvEnd }; diff --git a/cloud/filestore/libs/storage/tablet/helpers.cpp b/cloud/filestore/libs/storage/tablet/helpers.cpp index e9c784dedc..0d1e0ecb9a 100644 --- a/cloud/filestore/libs/storage/tablet/helpers.cpp +++ b/cloud/filestore/libs/storage/tablet/helpers.cpp @@ -87,7 +87,10 @@ NProto::TNode CopyAttrs(const NProto::TNode& src, ui32 mode) return node; } -void ConvertNodeFromAttrs(NProto::TNodeAttr& dst, ui64 id, const NProto::TNode& src) +void ConvertNodeFromAttrs( + NProto::TNodeAttr& dst, + ui64 id, + const NProto::TNode& src) { dst.SetId(id); dst.SetType(src.GetType()); @@ -101,6 +104,19 @@ void ConvertNodeFromAttrs(NProto::TNodeAttr& dst, ui64 id, const NProto::TNode& dst.SetLinks(src.GetLinks()); } +void ConvertAttrsToNode(const NProto::TNodeAttr& src, NProto::TNode* dst) +{ + dst->SetType(src.GetType()); + dst->SetMode(src.GetMode()); + dst->SetUid(src.GetUid()); + dst->SetGid(src.GetGid()); + dst->SetATime(src.GetATime()); + dst->SetMTime(src.GetMTime()); + dst->SetCTime(src.GetCTime()); + dst->SetSize(src.GetSize()); + dst->SetLinks(src.GetLinks()); +} + //////////////////////////////////////////////////////////////////////////////// NProto::TError ValidateNodeName(const TString& name) diff --git a/cloud/filestore/libs/storage/tablet/helpers.h b/cloud/filestore/libs/storage/tablet/helpers.h index 166fb27a28..98e40887c4 100644 --- a/cloud/filestore/libs/storage/tablet/helpers.h +++ b/cloud/filestore/libs/storage/tablet/helpers.h @@ -64,7 +64,8 @@ namespace NCloud::NFileStore::NStorage { //////////////////////////////////////////////////////////////////////////////// -enum ECopyAttrsMode { +enum ECopyAttrsMode +{ E_CM_CTIME = 1, // CTime E_CM_MTIME = 2, // MTime @@ -84,7 +85,12 @@ NProto::TNode CreateSocketAttrs(ui32 mode, ui32 uid, ui32 gid); NProto::TNode CopyAttrs(const NProto::TNode& src, ui32 mode = E_CM_CTIME); -void ConvertNodeFromAttrs(NProto::TNodeAttr& dst, ui64 id, const NProto::TNode& src); +void ConvertNodeFromAttrs( + NProto::TNodeAttr& dst, + ui64 id, + const NProto::TNode& src); + +void ConvertAttrsToNode(const NProto::TNodeAttr& src, NProto::TNode* dst); //////////////////////////////////////////////////////////////////////////////// diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp new file mode 100644 index 0000000000..92b7c01a89 --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp @@ -0,0 +1,272 @@ +#include "tablet_actor.h" + +#include "helpers.h" + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +using namespace NKikimr; +using namespace NKikimr::NTabletFlatExecutor; + +//////////////////////////////////////////////////////////////////////////////// + +void TIndexTabletActor::HandleUnsafeDeleteNode( + const TEvIndexTablet::TEvUnsafeDeleteNodeRequest::TPtr& ev, + const TActorContext& ctx) +{ + auto* msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + ev->Sender, + ev->Cookie, + msg->CallContext); + + AddTransaction(*requestInfo); + + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeDeleteNode: %s", + LogTag.c_str(), + msg->Record.DebugString().Quote().c_str()); + + ExecuteTx( + ctx, + std::move(requestInfo), + std::move(msg->Record)); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TIndexTabletActor::PrepareTx_UnsafeDeleteNode( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TUnsafeDeleteNode& args) +{ + Y_UNUSED(ctx); + + auto commitId = GetCurrentCommitId(); + + TIndexTabletDatabaseProxy db(tx.DB, args.NodeUpdates); + return ReadNode(db, args.Request.GetId(), commitId, args.Node); +} + +void TIndexTabletActor::ExecuteTx_UnsafeDeleteNode( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TUnsafeDeleteNode& args) +{ + TIndexTabletDatabaseProxy db(tx.DB, args.NodeUpdates); + + auto commitId = GenerateCommitId(); + if (commitId == InvalidCommitId) { + return RebootTabletOnCommitOverflow(ctx, "UnsafeDeleteNode"); + } + + if (!args.Node) { + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeDeleteNode: %s - node not found", + LogTag.c_str(), + args.Request.DebugString().Quote().c_str()); + return; + } + + args.Error = RemoveNode(db, *args.Node, args.Node->MinCommitId, commitId); +} + +void TIndexTabletActor::CompleteTx_UnsafeDeleteNode( + const TActorContext& ctx, + TTxIndexTablet::TUnsafeDeleteNode& args) +{ + RemoveTransaction(*args.RequestInfo); + + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeDeleteNode: %s, status: %s", + LogTag.c_str(), + args.Request.DebugString().Quote().c_str(), + FormatError(args.Error).c_str()); + + auto response = + std::make_unique( + std::move(args.Error)); + + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); +} + +//////////////////////////////////////////////////////////////////////////////// + +void TIndexTabletActor::HandleUnsafeUpdateNode( + const TEvIndexTablet::TEvUnsafeUpdateNodeRequest::TPtr& ev, + const TActorContext& ctx) +{ + auto* msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + ev->Sender, + ev->Cookie, + msg->CallContext); + + AddTransaction(*requestInfo); + + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeUpdateNode: %s", + LogTag.c_str(), + msg->Record.DebugString().Quote().c_str()); + + ExecuteTx( + ctx, + std::move(requestInfo), + std::move(msg->Record)); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TIndexTabletActor::PrepareTx_UnsafeUpdateNode( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TUnsafeUpdateNode& args) +{ + Y_UNUSED(ctx); + + auto commitId = GetCurrentCommitId(); + + TIndexTabletDatabaseProxy db(tx.DB, args.NodeUpdates); + return ReadNode(db, args.Request.GetNode().GetId(), commitId, args.Node); +} + +void TIndexTabletActor::ExecuteTx_UnsafeUpdateNode( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TUnsafeUpdateNode& args) +{ + TIndexTabletDatabaseProxy db(tx.DB, args.NodeUpdates); + + auto commitId = GenerateCommitId(); + if (commitId == InvalidCommitId) { + return RebootTabletOnCommitOverflow(ctx, "UnsafeUpdateNode"); + } + + NProto::TNode node; + + if (args.Node) { + node = args.Node->Attrs; + } else { + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeUpdateNode: %s - node not found, creating", + LogTag.c_str(), + args.Request.DebugString().Quote().c_str()); + + // creation here is still done via UpdateNode since CreateNode generates + // a new nodeId + } + + ConvertAttrsToNode(args.Request.GetNode(), &node); + UpdateNode( + db, + args.Request.GetNode().GetId(), + args.Node->MinCommitId, + commitId, + node, + args.Node->Attrs); +} + +void TIndexTabletActor::CompleteTx_UnsafeUpdateNode( + const TActorContext& ctx, + TTxIndexTablet::TUnsafeUpdateNode& args) +{ + RemoveTransaction(*args.RequestInfo); + + TString oldNode; + if (args.Node) { + oldNode = args.Node->Attrs.Utf8DebugString(); + } + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeUpdateNode: %s, old node: %s", + LogTag.c_str(), + args.Request.DebugString().Quote().c_str(), + oldNode.Quote().c_str()); + + auto response = + std::make_unique(); + + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); +} + +//////////////////////////////////////////////////////////////////////////////// + +void TIndexTabletActor::HandleUnsafeGetNode( + const TEvIndexTablet::TEvUnsafeGetNodeRequest::TPtr& ev, + const TActorContext& ctx) +{ + auto* msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + ev->Sender, + ev->Cookie, + msg->CallContext); + + AddTransaction(*requestInfo); + + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeGetNode: %s", + LogTag.c_str(), + msg->Record.DebugString().Quote().c_str()); + + ExecuteTx( + ctx, + std::move(requestInfo), + std::move(msg->Record)); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TIndexTabletActor::ValidateTx_UnsafeGetNode( + const TActorContext& ctx, + TTxIndexTablet::TUnsafeGetNode& args) +{ + Y_UNUSED(ctx); + Y_UNUSED(args); + + return true; +} + +bool TIndexTabletActor::PrepareTx_UnsafeGetNode( + const NActors::TActorContext& ctx, + IIndexTabletDatabase& db, + TTxIndexTablet::TUnsafeGetNode& args) +{ + Y_UNUSED(ctx); + + return ReadNode( + db, + args.Request.GetId(), + GetCurrentCommitId(), + args.Node); +} + +void TIndexTabletActor::CompleteTx_UnsafeGetNode( + const TActorContext& ctx, + TTxIndexTablet::TUnsafeGetNode& args) +{ + RemoveTransaction(*args.RequestInfo); + + TString node; + if (args.Node) { + node = args.Node->Attrs.Utf8DebugString(); + } + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s UnsafeGetNode: %s, node: %s", + LogTag.c_str(), + args.Request.DebugString().Quote().c_str(), + node.Quote().c_str()); + + auto response = + std::make_unique(); + if (args.Node) { + auto& attrs = *response->Record.MutableNode(); + ConvertNodeFromAttrs(attrs, args.Node->NodeId, args.Node->Attrs); + } + + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_tx.h b/cloud/filestore/libs/storage/tablet/tablet_tx.h index ef24699378..5643bc275d 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_tx.h +++ b/cloud/filestore/libs/storage/tablet/tablet_tx.h @@ -75,6 +75,8 @@ namespace NCloud::NFileStore::NStorage { xxx(GetNodeAttrBatch, __VA_ARGS__) \ xxx(GetNodeXAttr, __VA_ARGS__) \ xxx(ListNodeXAttr, __VA_ARGS__) \ + \ + xxx(UnsafeGetNode, __VA_ARGS__) \ // FILESTORE_TABLET_RO_TRANSACTIONS #define FILESTORE_TABLET_RW_TRANSACTIONS(xxx, ...) \ @@ -131,6 +133,9 @@ namespace NCloud::NFileStore::NStorage { \ xxx(DeleteOpLogEntry, __VA_ARGS__) \ xxx(CommitNodeCreationInFollower, __VA_ARGS__) \ + \ + xxx(UnsafeDeleteNode, __VA_ARGS__) \ + xxx(UnsafeUpdateNode, __VA_ARGS__) \ // FILESTORE_TABLET_RW_TRANSACTIONS #define FILESTORE_TABLET_TRANSACTIONS(xxx, ...) \ @@ -1965,7 +1970,7 @@ struct TTxIndexTablet NProto::TCreateNodeResponse Response; const ui64 EntryId; - explicit TCommitNodeCreationInFollower( + TCommitNodeCreationInFollower( TString sessionId, ui64 requestId, NProto::TCreateNodeResponse response, @@ -1980,6 +1985,71 @@ struct TTxIndexTablet { } }; + + // + // UnsafeNodeOps + // + + struct TUnsafeDeleteNode: TIndexStateNodeUpdates + { + const TRequestInfoPtr RequestInfo; + const NProtoPrivate::TUnsafeDeleteNodeRequest Request; + + TMaybe Node; + NProto::TError Error; + + TUnsafeDeleteNode( + TRequestInfoPtr requestInfo, + NProtoPrivate::TUnsafeDeleteNodeRequest request) + : RequestInfo(std::move(requestInfo)) + , Request(std::move(request)) + {} + + void Clear() + { + Node.Clear(); + Error.Clear(); + } + }; + + struct TUnsafeUpdateNode: TIndexStateNodeUpdates + { + const TRequestInfoPtr RequestInfo; + const NProtoPrivate::TUnsafeUpdateNodeRequest Request; + + TMaybe Node; + + TUnsafeUpdateNode( + TRequestInfoPtr requestInfo, + NProtoPrivate::TUnsafeUpdateNodeRequest request) + : RequestInfo(std::move(requestInfo)) + , Request(std::move(request)) + {} + + void Clear() + { + Node.Clear(); + } + }; + + struct TUnsafeGetNode + { + const TRequestInfoPtr RequestInfo; + const NProtoPrivate::TUnsafeGetNodeRequest Request; + TMaybe Node; + + TUnsafeGetNode( + TRequestInfoPtr requestInfo, + NProtoPrivate::TUnsafeGetNodeRequest request) + : RequestInfo(std::move(requestInfo)) + , Request(std::move(request)) + {} + + void Clear() + { + Node.Clear(); + } + }; }; } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/ya.make b/cloud/filestore/libs/storage/tablet/ya.make index 27d9d978b8..8da6d907bb 100644 --- a/cloud/filestore/libs/storage/tablet/ya.make +++ b/cloud/filestore/libs/storage/tablet/ya.make @@ -64,6 +64,7 @@ SRCS( tablet_actor_throttling.cpp tablet_actor_truncate.cpp tablet_actor_unlinknode.cpp + tablet_actor_unsafe_node_ops.cpp tablet_actor_updateconfig.cpp tablet_actor_waitready.cpp tablet_actor_writebatch.cpp diff --git a/cloud/filestore/private/api/protos/tablet.proto b/cloud/filestore/private/api/protos/tablet.proto index 9c375971ef..65712de038 100644 --- a/cloud/filestore/private/api/protos/tablet.proto +++ b/cloud/filestore/private/api/protos/tablet.proto @@ -601,3 +601,44 @@ message TWriteCompactionMapResponse // Optional error, set only if error happened. NCloud.NProto.TError Error = 1; } + +//////////////////////////////////////////////////////////////////////////////// +// Direct inode manipulation. + +message TUnsafeDeleteNodeRequest +{ + string FileSystemId = 1; + uint64 Id = 2; +} + +message TUnsafeDeleteNodeResponse +{ + // Optional error, set only if error happened. + NCloud.NProto.TError Error = 1; +} + +message TUnsafeUpdateNodeRequest +{ + string FileSystemId = 1; + NProto.TNodeAttr Node = 2; +} + +message TUnsafeUpdateNodeResponse +{ + // Optional error, set only if error happened. + NCloud.NProto.TError Error = 1; +} + +message TUnsafeGetNodeRequest +{ + string FileSystemId = 1; + uint64 Id = 2; +} + +message TUnsafeGetNodeResponse +{ + // Optional error, set only if error happened. + NCloud.NProto.TError Error = 1; + + NProto.TNodeAttr Node = 2; +} From 9ce627267330db7df96a7db6ee49487a9b7a0dfd Mon Sep 17 00:00:00 2001 From: qkrorlqr Date: Sat, 28 Sep 2024 18:21:53 +0000 Subject: [PATCH 2/4] issue-1795: tiny cleanup --- cloud/filestore/libs/storage/tablet/tablet_tx.h | 1 + cloud/filestore/private/api/protos/tablet.proto | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/filestore/libs/storage/tablet/tablet_tx.h b/cloud/filestore/libs/storage/tablet/tablet_tx.h index 5643bc275d..ccc3f80b32 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_tx.h +++ b/cloud/filestore/libs/storage/tablet/tablet_tx.h @@ -2036,6 +2036,7 @@ struct TTxIndexTablet { const TRequestInfoPtr RequestInfo; const NProtoPrivate::TUnsafeGetNodeRequest Request; + TMaybe Node; TUnsafeGetNode( diff --git a/cloud/filestore/private/api/protos/tablet.proto b/cloud/filestore/private/api/protos/tablet.proto index 65712de038..6003432639 100644 --- a/cloud/filestore/private/api/protos/tablet.proto +++ b/cloud/filestore/private/api/protos/tablet.proto @@ -639,6 +639,5 @@ message TUnsafeGetNodeResponse { // Optional error, set only if error happened. NCloud.NProto.TError Error = 1; - NProto.TNodeAttr Node = 2; } From caed3f7b994ae765a479625f3b090e62643b2087 Mon Sep 17 00:00:00 2001 From: qkrorlqr Date: Sat, 28 Sep 2024 19:42:40 +0000 Subject: [PATCH 3/4] issue-1795: private api Unsafe{Delete,Update,Get}Node actions + ut --- .../libs/storage/service/service_actor.h | 12 ++ .../storage/service/service_actor_actions.cpp | 12 ++ .../service_actor_actions_unsafe_node_ops.cpp | 167 ++++++++++++++++++ .../service/service_actor_actions_ut.cpp | 116 +++++++++++- cloud/filestore/libs/storage/service/ya.make | 1 + .../tablet/tablet_actor_unsafe_node_ops.cpp | 8 +- 6 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp diff --git a/cloud/filestore/libs/storage/service/service_actor.h b/cloud/filestore/libs/storage/service/service_actor.h index 96d5353d92..494236545f 100644 --- a/cloud/filestore/libs/storage/service/service_actor.h +++ b/cloud/filestore/libs/storage/service/service_actor.h @@ -189,6 +189,18 @@ class TStorageServiceActor final TRequestInfoPtr requestInfo, TString input); + NActors::IActorPtr CreateUnsafeDeleteNodeActionActor( + TRequestInfoPtr requestInfo, + TString input); + + NActors::IActorPtr CreateUnsafeUpdateNodeActionActor( + TRequestInfoPtr requestInfo, + TString input); + + NActors::IActorPtr CreateUnsafeGetNodeActionActor( + TRequestInfoPtr requestInfo, + TString input); + private: void RenderSessions(IOutputStream& out); void RenderLocalFileStores(IOutputStream& out); diff --git a/cloud/filestore/libs/storage/service/service_actor_actions.cpp b/cloud/filestore/libs/storage/service/service_actor_actions.cpp index 990dafb6a7..806be7146d 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions.cpp @@ -72,6 +72,18 @@ void TStorageServiceActor::HandleExecuteAction( "writecompactionmap", &TStorageServiceActor::CreateWriteCompactionMapActionActor }, + { + "unsafedeletenode", + &TStorageServiceActor::CreateUnsafeDeleteNodeActionActor + }, + { + "unsafeupdatenode", + &TStorageServiceActor::CreateUnsafeUpdateNodeActionActor + }, + { + "unsafegetnode", + &TStorageServiceActor::CreateUnsafeGetNodeActionActor + }, }; auto it = actions.find(action); diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp new file mode 100644 index 0000000000..22c0216e11 --- /dev/null +++ b/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp @@ -0,0 +1,167 @@ +#include "service_actor.h" + +#include +#include +#include +#include +#include + +#include + +#include + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +using namespace NKikimr; + +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +template +class TTabletActionActor final + : public TActorBootstrapped> +{ +private: + const TRequestInfoPtr RequestInfo; + const TString Input; + + using TBase = TActorBootstrapped>; + +public: + TTabletActionActor( + TRequestInfoPtr requestInfo, + TString input); + + void Bootstrap(const TActorContext& ctx); + +private: + void ReplyAndDie( + const TActorContext& ctx, + const TResponse::ProtoRecordType& responseRecord); + +private: + STFUNC(StateWork) + { + switch (ev->GetTypeRewrite()) { + HFunc(TResponse, HandleResponse); + + default: + HandleUnexpectedEvent(ev, TFileStoreComponents::SERVICE); + break; + } + } + + void HandleResponse( + const TResponse::TPtr& ev, + const TActorContext& ctx); +}; + +//////////////////////////////////////////////////////////////////////////////// + +template +TTabletActionActor::TTabletActionActor( + TRequestInfoPtr requestInfo, + TString input) + : RequestInfo(std::move(requestInfo)) + , Input(std::move(input)) +{} + +template +void TTabletActionActor::Bootstrap( + const TActorContext& ctx) +{ + typename TRequest::ProtoRecordType request; + if (!google::protobuf::util::JsonStringToMessage(Input, &request).ok()) { + ReplyAndDie( + ctx, + TErrorResponse(E_ARGUMENT, "Failed to parse input")); + return; + } + + if (!request.GetFileSystemId()) { + ReplyAndDie( + ctx, + TErrorResponse(E_ARGUMENT, "FileSystem id should be supplied")); + return; + } + + auto requestToTablet = std::make_unique(); + + requestToTablet->Record = std::move(request); + + NCloud::Send( + ctx, + MakeIndexTabletProxyServiceId(), + std::move(requestToTablet)); + + TBase::Become(&TTabletActionActor::StateWork); +} + +template +void TTabletActionActor::ReplyAndDie( + const TActorContext& ctx, + const TResponse::ProtoRecordType& response) +{ + auto msg = std::make_unique( + response.GetError()); + + google::protobuf::util::MessageToJsonString( + response, + msg->Record.MutableOutput()); + + NCloud::Reply(ctx, *RequestInfo, std::move(msg)); + TBase::Die(ctx); +} + +//////////////////////////////////////////////////////////////////////////////// + +template +void TTabletActionActor::HandleResponse( + const TResponse::TPtr& ev, + const TActorContext& ctx) +{ + ReplyAndDie(ctx, ev->Get()->Record); +} + +} // namespace + +IActorPtr TStorageServiceActor::CreateUnsafeDeleteNodeActionActor( + TRequestInfoPtr requestInfo, + TString input) +{ + using TUnsafeDeleteNodeActor = TTabletActionActor< + TEvIndexTablet::TEvUnsafeDeleteNodeRequest, + TEvIndexTablet::TEvUnsafeDeleteNodeResponse>; + return std::make_unique( + std::move(requestInfo), + std::move(input)); +} + +IActorPtr TStorageServiceActor::CreateUnsafeUpdateNodeActionActor( + TRequestInfoPtr requestInfo, + TString input) +{ + using TUnsafeUpdateNodeActor = TTabletActionActor< + TEvIndexTablet::TEvUnsafeUpdateNodeRequest, + TEvIndexTablet::TEvUnsafeUpdateNodeResponse>; + return std::make_unique( + std::move(requestInfo), + std::move(input)); +} + +IActorPtr TStorageServiceActor::CreateUnsafeGetNodeActionActor( + TRequestInfoPtr requestInfo, + TString input) +{ + using TUnsafeGetNodeActor = TTabletActionActor< + TEvIndexTablet::TEvUnsafeGetNodeRequest, + TEvIndexTablet::TEvUnsafeGetNodeResponse>; + return std::make_unique( + std::move(requestInfo), + std::move(input)); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp index 669969c161..435141a4bb 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp @@ -1,4 +1,6 @@ #include "service.h" +#include "cloud/filestore/private/api/protos/tablet.pb.h" +#include "google/protobuf/util/json_util.h" #include #include @@ -83,7 +85,8 @@ Y_UNIT_TEST_SUITE(TStorageServiceActionsTest) ui32 nodeIdx = env.CreateNode("nfs"); TServiceClient service(env.GetRuntime(), nodeIdx); - auto response = service.AssertExecuteActionFailed("NonExistingAction", "{}"); + auto response = + service.AssertExecuteActionFailed("NonExistingAction", "{}"); UNIT_ASSERT_VALUES_UNEQUAL(S_OK, response->GetStatus()); } @@ -179,6 +182,117 @@ Y_UNIT_TEST_SUITE(TStorageServiceActionsTest) true); } } + + Y_UNIT_TEST(ShouldPerformUnsafeNodeManipulations) + { + NProto::TStorageConfig config; + TTestEnv env{{}, config}; + env.CreateSubDomain("nfs"); + + ui32 nodeIdx = env.CreateNode("nfs"); + + TServiceClient service(env.GetRuntime(), nodeIdx); + + const TString fsId = "test"; + service.CreateFileStore(fsId, 1'000); + + auto headers = service.InitSession("test", "client"); + + service.CreateNode(headers, TCreateNodeArgs::File(RootNodeId, "file1")); + service.CreateNode(headers, TCreateNodeArgs::File(RootNodeId, "file2")); + + ui64 id1 = 0; + ui64 id2 = 0; + ui64 id3 = 0; + + { + auto r = service.ListNodes(headers, fsId, RootNodeId)->Record; + UNIT_ASSERT_VALUES_EQUAL(2, r.NodesSize()); + UNIT_ASSERT_VALUES_EQUAL(0, r.GetNodes(0).GetSize()); + UNIT_ASSERT_VALUES_EQUAL(0, r.GetNodes(1).GetSize()); + + id1 = r.GetNodes(0).GetId(); + id2 = r.GetNodes(1).GetId(); + + UNIT_ASSERT_VALUES_UNEQUAL(0, id1); + UNIT_ASSERT_VALUES_UNEQUAL(0, id2); + } + + id3 = Max(id1, id2) + 1; + + { + NProtoPrivate::TUnsafeUpdateNodeRequest request; + request.SetFileSystemId(fsId); + auto* node = request.MutableNode(); + node->SetId(id3); + node->SetSize(333); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + service.ExecuteAction("UnsafeUpdateNode", buf); + } + + { + NProtoPrivate::TUnsafeGetNodeRequest request; + request.SetFileSystemId(fsId); + request.SetId(id3); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + auto r = service.ExecuteAction("UnsafeGetNode", buf)->Record; + + NProtoPrivate::TUnsafeGetNodeResponse response; + UNIT_ASSERT(google::protobuf::util::JsonStringToMessage( + r.GetOutput(), + &response).ok()); + + UNIT_ASSERT_VALUES_EQUAL(id3, response.GetNode().GetId()); + UNIT_ASSERT_VALUES_EQUAL(333, response.GetNode().GetSize()); + } + + { + NProtoPrivate::TUnsafeUpdateNodeRequest request; + request.SetFileSystemId(fsId); + auto* node = request.MutableNode(); + node->SetId(id2); + node->SetSize(222); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + service.ExecuteAction("UnsafeUpdateNode", buf); + } + + { + auto r = service.ListNodes(headers, fsId, RootNodeId)->Record; + UNIT_ASSERT_VALUES_EQUAL(2, r.NodesSize()); + UNIT_ASSERT_VALUES_EQUAL(0, r.GetNodes(0).GetSize()); + UNIT_ASSERT_VALUES_EQUAL(222, r.GetNodes(1).GetSize()); + } + + { + NProtoPrivate::TUnsafeDeleteNodeRequest request; + request.SetFileSystemId(fsId); + request.SetId(id3); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + service.ExecuteAction("UnsafeDeleteNode", buf); + } + + { + NProtoPrivate::TUnsafeGetNodeRequest request; + request.SetFileSystemId(fsId); + request.SetId(id3); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + auto r = service.ExecuteAction("UnsafeGetNode", buf)->Record; + + NProtoPrivate::TUnsafeGetNodeResponse response; + UNIT_ASSERT(google::protobuf::util::JsonStringToMessage( + r.GetOutput(), + &response).ok()); + + UNIT_ASSERT(!response.HasNode()); + } + + service.DestroySession(headers); + } } } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/ya.make b/cloud/filestore/libs/storage/service/ya.make index 27ca295533..d01a17b9dd 100644 --- a/cloud/filestore/libs/storage/service/ya.make +++ b/cloud/filestore/libs/storage/service/ya.make @@ -13,6 +13,7 @@ SRCS( service_actor_actions_get_storage_config_fields.cpp service_actor_actions_get_storage_config.cpp service_actor_actions_reassign_tablet.cpp + service_actor_actions_unsafe_node_ops.cpp service_actor_actions_write_compaction_map.cpp service_actor_actions.cpp service_actor_alterfs.cpp diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp index 92b7c01a89..cef98ff1bd 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_unsafe_node_ops.cpp @@ -145,10 +145,14 @@ void TIndexTabletActor::ExecuteTx_UnsafeUpdateNode( return RebootTabletOnCommitOverflow(ctx, "UnsafeUpdateNode"); } + NProto::TNode prevNode; NProto::TNode node; + ui64 nodeCommitId = commitId; if (args.Node) { + prevNode = args.Node->Attrs; node = args.Node->Attrs; + nodeCommitId = args.Node->MinCommitId; } else { LOG_WARN(ctx, TFileStoreComponents::TABLET, "%s UnsafeUpdateNode: %s - node not found, creating", @@ -163,10 +167,10 @@ void TIndexTabletActor::ExecuteTx_UnsafeUpdateNode( UpdateNode( db, args.Request.GetNode().GetId(), - args.Node->MinCommitId, + nodeCommitId, commitId, node, - args.Node->Attrs); + prevNode); } void TIndexTabletActor::CompleteTx_UnsafeUpdateNode( From 8fdf232c55a5d6f0b2f94eb39ec31a6946f3009e Mon Sep 17 00:00:00 2001 From: qkrorlqr Date: Sat, 28 Sep 2024 19:45:16 +0000 Subject: [PATCH 4/4] issue-1795: cleanup --- .../service/service_actor_actions_unsafe_node_ops.cpp | 5 +---- .../libs/storage/service/service_actor_actions_ut.cpp | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp index 22c0216e11..0ba3cc220a 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp @@ -54,9 +54,7 @@ class TTabletActionActor final } } - void HandleResponse( - const TResponse::TPtr& ev, - const TActorContext& ctx); + void HandleResponse(const TResponse::TPtr& ev, const TActorContext& ctx); }; //////////////////////////////////////////////////////////////////////////////// @@ -89,7 +87,6 @@ void TTabletActionActor::Bootstrap( } auto requestToTablet = std::make_unique(); - requestToTablet->Record = std::move(request); NCloud::Send( diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp index 435141a4bb..a8fd01c774 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp @@ -1,13 +1,13 @@ #include "service.h" -#include "cloud/filestore/private/api/protos/tablet.pb.h" -#include "google/protobuf/util/json_util.h" #include #include #include #include +#include #include +#include namespace NCloud::NFileStore::NStorage {