From f4331316c752388679af53f68f96258d565d8feb Mon Sep 17 00:00:00 2001 From: Andrei Strelkovskii Date: Fri, 25 Oct 2024 19:27:22 +0200 Subject: [PATCH] issue-2137: GetStorageStats private API action (#2350) --- .../libs/storage/service/service_actor.h | 4 + .../storage/service/service_actor_actions.cpp | 4 + .../service/service_actor_actions_stats.cpp | 26 ++++ .../service_actor_actions_unsafe_node_ops.cpp | 118 +---------------- .../service/service_actor_actions_ut.cpp | 64 +++++++++ .../storage/service/tablet_action_actor.cpp | 1 + .../storage/service/tablet_action_actor.h | 122 ++++++++++++++++++ cloud/filestore/libs/storage/service/ya.make | 2 + 8 files changed, 225 insertions(+), 116 deletions(-) create mode 100644 cloud/filestore/libs/storage/service/service_actor_actions_stats.cpp create mode 100644 cloud/filestore/libs/storage/service/tablet_action_actor.cpp create mode 100644 cloud/filestore/libs/storage/service/tablet_action_actor.h diff --git a/cloud/filestore/libs/storage/service/service_actor.h b/cloud/filestore/libs/storage/service/service_actor.h index af3a9a3ab70..76bdc131b03 100644 --- a/cloud/filestore/libs/storage/service/service_actor.h +++ b/cloud/filestore/libs/storage/service/service_actor.h @@ -201,6 +201,10 @@ class TStorageServiceActor final TRequestInfoPtr requestInfo, TString input); + NActors::IActorPtr CreateGetStorageStatsActionActor( + 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 6b1b1b288bb..20e0e1c0456 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions.cpp @@ -84,6 +84,10 @@ void TStorageServiceActor::HandleExecuteAction( "unsafegetnode", &TStorageServiceActor::CreateUnsafeGetNodeActionActor }, + { + "getstoragestats", + &TStorageServiceActor::CreateGetStorageStatsActionActor + }, }; auto it = actions.find(action); diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_stats.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_stats.cpp new file mode 100644 index 00000000000..49242e4110f --- /dev/null +++ b/cloud/filestore/libs/storage/service/service_actor_actions_stats.cpp @@ -0,0 +1,26 @@ +#include "service_actor.h" + +#include "tablet_action_actor.h" + +#include +#include + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +//////////////////////////////////////////////////////////////////////////////// + +IActorPtr TStorageServiceActor::CreateGetStorageStatsActionActor( + TRequestInfoPtr requestInfo, + TString input) +{ + using TGetStorageStatsActor = TTabletActionActor< + TEvIndexTablet::TEvGetStorageStatsRequest, + TEvIndexTablet::TEvGetStorageStatsResponse>; + 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_unsafe_node_ops.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_unsafe_node_ops.cpp index 0ba3cc220a3..bb0b7ee57ff 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 @@ -1,130 +1,16 @@ #include "service_actor.h" -#include +#include "tablet_action_actor.h" + #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) 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 a8fd01c7746..5d2e2e1de22 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions_ut.cpp @@ -293,6 +293,70 @@ Y_UNIT_TEST_SUITE(TStorageServiceActionsTest) service.DestroySession(headers); } + + Y_UNIT_TEST(ShouldGetStorageStats) + { + 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"); + + const auto handle = service.CreateHandle( + headers, + fsId, + RootNodeId, + "file", + TCreateHandleArgs::CREATE + )->Record; + const auto nodeId = handle.GetNodeAttr().GetId(); + const auto handleId = handle.GetHandle(); + + service.WriteData( + headers, + fsId, + nodeId, + handleId, + 0, + TString(256_KB, 'a')); + + service.WriteData( + headers, + fsId, + nodeId, + handleId, + 256_KB, + TString(256_KB, 'a')); + + { + NProtoPrivate::TGetStorageStatsRequest request; + request.SetFileSystemId(fsId); + request.SetCompactionRangeCountByCompactionScore(2); + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + const auto response = service.ExecuteAction("GetStorageStats", buf); + NProtoPrivate::TGetStorageStatsResponse record; + auto status = google::protobuf::util::JsonStringToMessage( + response->Record.GetOutput(), + &record); + const auto& stats = record.GetStats(); + const auto& compactionRanges = stats.GetCompactionRangeStats(); + UNIT_ASSERT_VALUES_EQUAL(1, stats.GetUsedNodesCount()); + UNIT_ASSERT_VALUES_EQUAL(2, stats.GetUsedCompactionRanges()); + UNIT_ASSERT_VALUES_EQUAL(2, compactionRanges.size()); + UNIT_ASSERT_VALUES_EQUAL(1, compactionRanges[0].GetBlobCount()); + UNIT_ASSERT_VALUES_EQUAL(1, compactionRanges[1].GetBlobCount()); + } + + service.DestroySession(headers); + } } } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/tablet_action_actor.cpp b/cloud/filestore/libs/storage/service/tablet_action_actor.cpp new file mode 100644 index 00000000000..a9e58e302c4 --- /dev/null +++ b/cloud/filestore/libs/storage/service/tablet_action_actor.cpp @@ -0,0 +1 @@ +#include "tablet_action_actor.h" diff --git a/cloud/filestore/libs/storage/service/tablet_action_actor.h b/cloud/filestore/libs/storage/service/tablet_action_actor.h new file mode 100644 index 00000000000..5d47ccb91e3 --- /dev/null +++ b/cloud/filestore/libs/storage/service/tablet_action_actor.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include + +namespace NCloud::NFileStore::NStorage { + +//////////////////////////////////////////////////////////////////////////////// + +template +class TTabletActionActor final + : public NActors::TActorBootstrapped> +{ +private: + const TRequestInfoPtr RequestInfo; + const TString Input; + + using TBase = + NActors::TActorBootstrapped>; + +public: + TTabletActionActor( + TRequestInfoPtr requestInfo, + TString input); + + void Bootstrap(const NActors::TActorContext& ctx); + +private: + void ReplyAndDie( + const NActors::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 NActors::TActorContext& ctx); +}; + +//////////////////////////////////////////////////////////////////////////////// + +template +TTabletActionActor::TTabletActionActor( + TRequestInfoPtr requestInfo, + TString input) + : RequestInfo(std::move(requestInfo)) + , Input(std::move(input)) +{} + +template +void TTabletActionActor::Bootstrap( + const NActors::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 NActors::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 NActors::TActorContext& ctx) +{ + ReplyAndDie(ctx, ev->Get()->Record); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/ya.make b/cloud/filestore/libs/storage/service/ya.make index 1ced009520e..ec9f0b203db 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_stats.cpp service_actor_actions_unsafe_node_ops.cpp service_actor_actions_write_compaction_map.cpp service_actor_actions.cpp @@ -40,6 +41,7 @@ SRCS( service_actor_update_stats.cpp service_actor_writedata.cpp service_state.cpp + tablet_action_actor.cpp ) PEERDIR(