From 1fbce291abaf027e0d358d5e72a5eb8ef6dee242 Mon Sep 17 00:00:00 2001 From: Maxim Deb Natkh Date: Mon, 19 Aug 2024 10:45:05 +0200 Subject: [PATCH] [Filestore, merge to stable] add force operation to delete all zero compaction stat ranges; add action to write specified data to compaction map table, nfs-client.txt, support aliases for filestore names (#1817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add force operation to delete all zero compaction stat ranges; add aсtion to write specified data to compaction map table (#1690) * add force operation to delete all zero compaction stat ranges; add action to write specified data to compaction map table * fix-issues * fix issues * fix * [Filestore] add `nfs-client.txt` config for filestore analogous to the `nbs-client.txt` one (#1687) add nfs-client.txt config for filestore analogous to the nbs-client one * issue-1794: support aliases for filestore names (#1774) * issue-1794: support aliases for filestore names * fix cmakelists * issue-1794: fixed use-after-free in fs search by alias, not making a new THashMap upon each alias search, removed incorrect TABLET_VERIFY in TIndexTabletActor::CompleteTx_CreateSession (#1816) * issue-1794: fixed use-after-free in fs search by alias, not making a new THashMap upon each alias search, removed incorrect TABLET_VERIFY in TIndexTabletActor::CompleteTx_CreateSession * issue-1794: fixed use-after-free in fs search by alias, not making a new THashMap upon each alias search, removed incorrect TABLET_VERIFY in TIndexTabletActor::CompleteTx_CreateSession - fixed comment * fix build: exclude TCertificate from config.cpp * fix build * fix build * fix build --------- Co-authored-by: Darya Frolova <47457802+WilyTiger@users.noreply.github.com> Co-authored-by: Darya Frolova Co-authored-by: Andrei Strelkovskii --- cloud/blockstore/apps/client/lib/command.cpp | 5 +- cloud/filestore/apps/client/lib/command.cpp | 14 ++ cloud/filestore/apps/client/lib/command.h | 1 + cloud/filestore/config/storage.proto | 15 ++ cloud/filestore/libs/storage/api/tablet.h | 4 + cloud/filestore/libs/storage/core/config.cpp | 51 +++++++ cloud/filestore/libs/storage/core/config.h | 5 + .../service/CMakeLists.darwin-x86_64.txt | 1 + .../service/CMakeLists.linux-aarch64.txt | 1 + .../service/CMakeLists.linux-x86_64.txt | 1 + .../service/CMakeLists.windows-x86_64.txt | 1 + .../libs/storage/service/service_actor.h | 4 + .../storage/service/service_actor_actions.cpp | 4 + ...ice_actor_actions_write_compaction_map.cpp | 138 ++++++++++++++++++ .../service/service_actor_createsession.cpp | 7 +- .../libs/storage/service/service_ut.cpp | 129 ++++++++++++++++ cloud/filestore/libs/storage/service/ya.make | 1 + .../tablet/CMakeLists.darwin-x86_64.txt | 2 + .../tablet/CMakeLists.linux-aarch64.txt | 2 + .../tablet/CMakeLists.linux-x86_64.txt | 2 + .../tablet/CMakeLists.windows-x86_64.txt | 2 + .../libs/storage/tablet/tablet_actor.cpp | 21 ++- .../libs/storage/tablet/tablet_actor.h | 2 + .../tablet/tablet_actor_compactionforced.cpp | 22 +++ .../tablet/tablet_actor_createsession.cpp | 14 +- ...et_actor_delete_zero_compaction_ranges.cpp | 77 ++++++++++ .../storage/tablet/tablet_actor_loadstate.cpp | 3 + .../tablet/tablet_actor_monitoring.cpp | 56 ++++++- .../tablet_actor_write_compactionmap.cpp | 74 ++++++++++ .../libs/storage/tablet/tablet_database.cpp | 18 ++- .../libs/storage/tablet/tablet_database.h | 1 + .../libs/storage/tablet/tablet_private.h | 21 +++ .../filestore/libs/storage/tablet/tablet_tx.h | 44 ++++++ .../libs/storage/tablet/tablet_ut_data.cpp | 86 +++++++++++ cloud/filestore/libs/storage/tablet/ya.make | 2 + .../tablet_proxy/tablet_proxy_actor.cpp | 6 +- .../storage/tablet_proxy/tablet_proxy_ut.cpp | 56 +++++++ .../libs/storage/testlib/tablet_client.h | 28 ++++ .../storage/testlib/tablet_proxy_client.h | 8 + .../filestore/private/api/protos/tablet.proto | 16 ++ .../core/tools/ops/config_generator/main.go | 10 +- 41 files changed, 932 insertions(+), 23 deletions(-) create mode 100644 cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp create mode 100644 cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp create mode 100644 cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp diff --git a/cloud/blockstore/apps/client/lib/command.cpp b/cloud/blockstore/apps/client/lib/command.cpp index aa5a161e43..276315c585 100644 --- a/cloud/blockstore/apps/client/lib/command.cpp +++ b/cloud/blockstore/apps/client/lib/command.cpp @@ -122,6 +122,7 @@ TCommand::TCommand(IBlockStorePtr client) << "config file name. Default is " << DefaultConfigFile) .RequiredArgument("STR") + .DefaultValue(DefaultConfigFile) .StoreResult(&ConfigFile); Opts.AddLongOption("iam-config") @@ -610,10 +611,8 @@ TString TCommand::GetIamTokenFromClient() void TCommand::InitClientConfig() { NProto::TClientAppConfig appConfig; - if (ConfigFile) { + if (NFs::Exists(ConfigFile)) { ParseFromTextFormat(ConfigFile, appConfig); - } else if (NFs::Exists(DefaultConfigFile)) { - ParseFromTextFormat(DefaultConfigFile, appConfig); } auto& clientConfig = *appConfig.MutableClientConfig(); diff --git a/cloud/filestore/apps/client/lib/command.cpp b/cloud/filestore/apps/client/lib/command.cpp index 28659479b0..5d2733ce1a 100644 --- a/cloud/filestore/apps/client/lib/command.cpp +++ b/cloud/filestore/apps/client/lib/command.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ namespace { constexpr TDuration WaitTimeout = TDuration::Seconds(1); +const TString DefaultConfigFile = "/Berkanavt/nfs-server/cfg/nfs-client.txt"; const TString DefaultIamTokenFile = "~/.nfs-client/iam-token"; //////////////////////////////////////////////////////////////////////////////// @@ -103,6 +105,14 @@ TCommand::TCommand() .RequiredArgument("STR") .StoreResult(&IamTokenFile); + Opts.AddLongOption("config") + .Help(TStringBuilder() + << "config file name. Default is " + << DefaultConfigFile) + .RequiredArgument("STR") + .DefaultValue(DefaultConfigFile) + .StoreResult(&ConfigFile); + Opts.AddLongOption("json") .StoreTrue(&JsonOutput); } @@ -174,6 +184,10 @@ void TCommand::Init() Scheduler = CreateScheduler(); NProto::TClientConfig config; + if (NFs::Exists(ConfigFile)) { + ParseFromTextFormat(ConfigFile, config); + } + if (ServerAddress) { config.SetHost(ServerAddress); } diff --git a/cloud/filestore/apps/client/lib/command.h b/cloud/filestore/apps/client/lib/command.h index f8b640748a..6c2983535c 100644 --- a/cloud/filestore/apps/client/lib/command.h +++ b/cloud/filestore/apps/client/lib/command.h @@ -53,6 +53,7 @@ class TCommand ui32 SecurePort = 0; bool SkipCertVerification = false; TString IamTokenFile; + TString ConfigFile; TClientConfigPtr ClientConfig; diff --git a/cloud/filestore/config/storage.proto b/cloud/filestore/config/storage.proto index e06f2ce017..8b3058b2c4 100644 --- a/cloud/filestore/config/storage.proto +++ b/cloud/filestore/config/storage.proto @@ -312,4 +312,19 @@ message TStorageConfig // Enables ThreeStageWrite for unaligned requests. optional bool UnalignedThreeStageWriteEnabled = 366; + + // Number of ranges with zero compaction stats to delete per tx. + optional uint32 MaxZeroCompactionRangesToDeletePerTx = 367; + + // Mapping allowing for multiple fs ids to point to the same fs + message TFilestoreAliasEntry + { + optional string Alias = 1; + optional string FsId = 2; + } + message TFilestoreAliases + { + repeated TFilestoreAliasEntry Entries = 1; + } + optional TFilestoreAliases FilestoreAliases = 368; } diff --git a/cloud/filestore/libs/storage/api/tablet.h b/cloud/filestore/libs/storage/api/tablet.h index a96ba32971..4d285c0ecd 100644 --- a/cloud/filestore/libs/storage/api/tablet.h +++ b/cloud/filestore/libs/storage/api/tablet.h @@ -31,6 +31,7 @@ namespace NCloud::NFileStore::NStorage { xxx(ConfigureAsFollower, __VA_ARGS__) \ xxx(GetStorageConfig, __VA_ARGS__) \ xxx(GetNodeAttrBatch, __VA_ARGS__) \ + xxx(WriteCompactionMap, __VA_ARGS__) \ // FILESTORE_TABLET_REQUESTS //////////////////////////////////////////////////////////////////////////////// @@ -93,6 +94,9 @@ struct TEvIndexTablet EvGetNodeAttrBatchRequest = EvBegin + 31, EvGetNodeAttrBatchResponse, + EvWriteCompactionMapRequest = EvBegin + 33, + EvWriteCompactionMapResponse, + EvEnd }; diff --git a/cloud/filestore/libs/storage/core/config.cpp b/cloud/filestore/libs/storage/core/config.cpp index 1f2952d95c..af1eda2dc8 100644 --- a/cloud/filestore/libs/storage/core/config.cpp +++ b/cloud/filestore/libs/storage/core/config.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -12,6 +13,8 @@ namespace { //////////////////////////////////////////////////////////////////////////////// +using TAliases = NProto::TStorageConfig::TFilestoreAliases; + #define FILESTORE_STORAGE_CONFIG(xxx) \ xxx(SchemeShardDir, TString, "/Root" )\ \ @@ -168,8 +171,14 @@ namespace { xxx(AllowFileStoreForceDestroy, bool, false )\ xxx(BlobCompressionRate, ui32, 0 )\ xxx(BlobCompressionCodec, TString, "lz4" )\ + \ + xxx(MaxZeroCompactionRangesToDeletePerTx, ui32, 10000 )\ // FILESTORE_STORAGE_CONFIG +#define FILESTORE_STORAGE_CONFIG_REF(xxx) \ + xxx(FilestoreAliases, TAliases, {} )\ +// FILESTORE_STORAGE_CONFIG_REF + #define FILESTORE_DECLARE_CONFIG(name, type, value) \ Y_DECLARE_UNUSED static const type Default##name = value; \ // FILESTORE_DECLARE_CONFIG @@ -186,6 +195,12 @@ bool IsEmpty(const T& t) return !t; } +template <> +bool IsEmpty(const TAliases& value) +{ + return value.GetEntries().empty(); +} + template TTarget ConvertValue(const TSource& value) { @@ -218,6 +233,16 @@ void DumpImpl(const T& t, IOutputStream& os) os << t; } +template <> +void DumpImpl(const TAliases& value, IOutputStream& os) +{ + os << "{ "; + for (const auto& x: value.GetEntries()) { + os << x.GetAlias() << ": " << x.GetFsId() << ", "; + } + os << " }"; +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -234,6 +259,17 @@ FILESTORE_STORAGE_CONFIG(FILESTORE_CONFIG_GETTER) #undef FILESTORE_CONFIG_GETTER +#define FILESTORE_CONFIG_GETTER_REF(name, type, ...) \ +const type& TStorageConfig::Get##name() const \ +{ \ + return ProtoConfig.Get##name(); \ +} \ +// FILESTORE_CONFIG_GETTER_REF + +FILESTORE_STORAGE_CONFIG_REF(FILESTORE_CONFIG_GETTER_REF) + +#undef FILESTORE_CONFIG_GETTER_REF + void TStorageConfig::Dump(IOutputStream& out) const { #define FILESTORE_DUMP_CONFIG(name, ...) \ @@ -243,6 +279,7 @@ void TStorageConfig::Dump(IOutputStream& out) const // FILESTORE_DUMP_CONFIG FILESTORE_STORAGE_CONFIG(FILESTORE_DUMP_CONFIG); + FILESTORE_STORAGE_CONFIG_REF(FILESTORE_DUMP_CONFIG); #undef FILESTORE_DUMP_CONFIG } @@ -260,6 +297,7 @@ void TStorageConfig::DumpHtml(IOutputStream& out) const TABLE_CLASS("table table-condensed") { TABLEBODY() { FILESTORE_STORAGE_CONFIG(FILESTORE_DUMP_CONFIG); + FILESTORE_STORAGE_CONFIG_REF(FILESTORE_DUMP_CONFIG); } } } @@ -284,6 +322,7 @@ void TStorageConfig::DumpOverridesHtml(IOutputStream& out) const TABLE_CLASS("table table-condensed") { TABLEBODY() { FILESTORE_STORAGE_CONFIG(FILESTORE_DUMP_CONFIG); + FILESTORE_STORAGE_CONFIG_REF(FILESTORE_DUMP_CONFIG); } } } @@ -329,4 +368,16 @@ const NProto::TStorageConfig& TStorageConfig::GetStorageConfigProto() const return ProtoConfig; } +const TString* TStorageConfig::FindFileSystemIdByAlias( + const TString& alias) const +{ + const auto& entries = GetFilestoreAliases().GetEntries(); + for (const auto& entry: entries) { + if (entry.GetAlias() == alias) { + return &entry.GetFsId(); + } + } + return nullptr; +} + } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/core/config.h b/cloud/filestore/libs/storage/core/config.h index 307dd1505e..98f6de384d 100644 --- a/cloud/filestore/libs/storage/core/config.h +++ b/cloud/filestore/libs/storage/core/config.h @@ -214,6 +214,8 @@ class TStorageConfig bool GetAllowFileStoreForceDestroy() const; + ui32 GetMaxZeroCompactionRangesToDeletePerTx() const; + void Dump(IOutputStream& out) const; void DumpHtml(IOutputStream& out) const; void DumpOverridesHtml(IOutputStream& out) const; @@ -222,6 +224,9 @@ class TStorageConfig TString GetBlobCompressionCodec() const; const NProto::TStorageConfig& GetStorageConfigProto() const; + + const NProto::TStorageConfig::TFilestoreAliases& GetFilestoreAliases() const; + const TString* FindFileSystemIdByAlias(const TString& alias) const; }; } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/CMakeLists.darwin-x86_64.txt b/cloud/filestore/libs/storage/service/CMakeLists.darwin-x86_64.txt index 6f50c9dfa8..9b37bfce98 100644 --- a/cloud/filestore/libs/storage/service/CMakeLists.darwin-x86_64.txt +++ b/cloud/filestore/libs/storage/service/CMakeLists.darwin-x86_64.txt @@ -40,6 +40,7 @@ target_sources(filestore-libs-storage-service PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config_fields.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_reassign_tablet.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_alterfs.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_complete.cpp diff --git a/cloud/filestore/libs/storage/service/CMakeLists.linux-aarch64.txt b/cloud/filestore/libs/storage/service/CMakeLists.linux-aarch64.txt index 07849ef90c..faab313984 100644 --- a/cloud/filestore/libs/storage/service/CMakeLists.linux-aarch64.txt +++ b/cloud/filestore/libs/storage/service/CMakeLists.linux-aarch64.txt @@ -41,6 +41,7 @@ target_sources(filestore-libs-storage-service PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config_fields.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_reassign_tablet.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_alterfs.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_complete.cpp diff --git a/cloud/filestore/libs/storage/service/CMakeLists.linux-x86_64.txt b/cloud/filestore/libs/storage/service/CMakeLists.linux-x86_64.txt index 35ceadc25c..b563f2fde2 100644 --- a/cloud/filestore/libs/storage/service/CMakeLists.linux-x86_64.txt +++ b/cloud/filestore/libs/storage/service/CMakeLists.linux-x86_64.txt @@ -41,6 +41,7 @@ target_sources(filestore-libs-storage-service PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config_fields.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_reassign_tablet.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_alterfs.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_complete.cpp diff --git a/cloud/filestore/libs/storage/service/CMakeLists.windows-x86_64.txt b/cloud/filestore/libs/storage/service/CMakeLists.windows-x86_64.txt index 6f50c9dfa8..9b37bfce98 100644 --- a/cloud/filestore/libs/storage/service/CMakeLists.windows-x86_64.txt +++ b/cloud/filestore/libs/storage/service/CMakeLists.windows-x86_64.txt @@ -40,6 +40,7 @@ target_sources(filestore-libs-storage-service PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_get_storage_config_fields.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_reassign_tablet.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_actions.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_alterfs.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/service/service_actor_complete.cpp diff --git a/cloud/filestore/libs/storage/service/service_actor.h b/cloud/filestore/libs/storage/service/service_actor.h index 15acdcd4c9..461cd389e0 100644 --- a/cloud/filestore/libs/storage/service/service_actor.h +++ b/cloud/filestore/libs/storage/service/service_actor.h @@ -185,6 +185,10 @@ class TStorageServiceActor final TRequestInfoPtr requestInfo, TString input); + NActors::IActorPtr CreateWriteCompactionMapActionActor( + 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 7892b6968d..990dafb6a7 100644 --- a/cloud/filestore/libs/storage/service/service_actor_actions.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_actions.cpp @@ -68,6 +68,10 @@ void TStorageServiceActor::HandleExecuteAction( "getstorageconfig", &TStorageServiceActor::CreateGetStorageConfigActionActor }, + { + "writecompactionmap", + &TStorageServiceActor::CreateWriteCompactionMapActionActor + }, }; auto it = actions.find(action); diff --git a/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp b/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp new file mode 100644 index 0000000000..1c8b589cfe --- /dev/null +++ b/cloud/filestore/libs/storage/service/service_actor_actions_write_compaction_map.cpp @@ -0,0 +1,138 @@ +#include "service_actor.h" + +#include +#include +#include +#include +#include + +#include + +#include + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +using namespace NKikimr; + +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +class TWriteCompactionMapActionActor final + : public TActorBootstrapped +{ +private: + const TRequestInfoPtr RequestInfo; + const TString Input; + +public: + TWriteCompactionMapActionActor( + TRequestInfoPtr requestInfo, + TString input); + + void Bootstrap(const TActorContext& ctx); + +private: + void ReplyAndDie( + const TActorContext& ctx, + const NProtoPrivate::TWriteCompactionMapResponse& response); +private: + STFUNC(StateWork); + + void HandleWriteCompactionMapResponse( + const TEvIndexTablet::TEvWriteCompactionMapResponse::TPtr& ev, + const TActorContext& ctx); +}; + +//////////////////////////////////////////////////////////////////////////////// + +TWriteCompactionMapActionActor::TWriteCompactionMapActionActor( + TRequestInfoPtr requestInfo, + TString input) + : RequestInfo(std::move(requestInfo)) + , Input(std::move(input)) +{} + +void TWriteCompactionMapActionActor::Bootstrap(const TActorContext& ctx) +{ + NProtoPrivate::TWriteCompactionMapRequest 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)); + + Become(&TThis::StateWork); +} + +void TWriteCompactionMapActionActor::ReplyAndDie( + const TActorContext& ctx, + const NProtoPrivate::TWriteCompactionMapResponse& response) +{ + auto msg = std::make_unique( + response.GetError()); + + google::protobuf::util::MessageToJsonString( + response, + msg->Record.MutableOutput()); + + NCloud::Reply(ctx, *RequestInfo, std::move(msg)); + Die(ctx); +} + +//////////////////////////////////////////////////////////////////////////////// + +void TWriteCompactionMapActionActor::HandleWriteCompactionMapResponse( + const TEvIndexTablet::TEvWriteCompactionMapResponse::TPtr& ev, + const TActorContext& ctx) +{ + ReplyAndDie(ctx, ev->Get()->Record); +} + +//////////////////////////////////////////////////////////////////////////////// + +STFUNC(TWriteCompactionMapActionActor::StateWork) +{ + switch (ev->GetTypeRewrite()) { + HFunc( + TEvIndexTablet::TEvWriteCompactionMapResponse, + HandleWriteCompactionMapResponse); + + default: + HandleUnexpectedEvent(ev, TFileStoreComponents::SERVICE); + break; + } +} + +} // namespace + +IActorPtr TStorageServiceActor::CreateWriteCompactionMapActionActor( + TRequestInfoPtr requestInfo, + TString input) +{ + return std::make_unique( + std::move(requestInfo), + std::move(input)); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/service_actor_createsession.cpp b/cloud/filestore/libs/storage/service/service_actor_createsession.cpp index 33e1a1b664..cbaeb5930c 100644 --- a/cloud/filestore/libs/storage/service/service_actor_createsession.cpp +++ b/cloud/filestore/libs/storage/service/service_actor_createsession.cpp @@ -652,7 +652,12 @@ void TStorageServiceActor::HandleCreateSession( const auto* msg = ev->Get(); const auto& clientId = GetClientId(msg->Record); - const auto& fileSystemId = msg->Record.GetFileSystemId(); + TString fileSystemId = msg->Record.GetFileSystemId(); + if (const auto* realId = + StorageConfig->FindFileSystemIdByAlias(fileSystemId)) + { + fileSystemId = *realId; + } const auto& checkpointId = msg->Record.GetCheckpointId(); auto originFqdn = GetOriginFqdn(msg->Record); diff --git a/cloud/filestore/libs/storage/service/service_ut.cpp b/cloud/filestore/libs/storage/service/service_ut.cpp index 759139a524..107197fa61 100644 --- a/cloud/filestore/libs/storage/service/service_ut.cpp +++ b/cloud/filestore/libs/storage/service/service_ut.cpp @@ -5213,6 +5213,135 @@ Y_UNIT_TEST_SUITE(TStorageServiceTest) createSessionResponse->GetErrorReason()); service.AssertDestroyFileStoreFailed(fsId, true); } + + Y_UNIT_TEST(ShouldUseAliasesForRequestsForwarding) + { + const TString originalFs = "test"; + const TString mirroredFs = "test-mirrored"; + + NProto::TStorageConfig::TFilestoreAliasEntry entry; + entry.SetAlias(mirroredFs); + entry.SetFsId(originalFs); + NProto::TStorageConfig::TFilestoreAliases aliases; + aliases.MutableEntries()->Add(std::move(entry)); + + NProto::TStorageConfig config; + config.MutableFilestoreAliases()->Swap(&aliases); + + TTestEnv env({}, config); + env.CreateSubDomain("nfs"); + + ui32 nodeIdx = env.CreateNode("nfs"); + + + TServiceClient service(env.GetRuntime(), nodeIdx); + service.CreateFileStore(originalFs, 1000); + service.CreateFileStore(mirroredFs, 1000); + + auto originalHeaders = service.InitSession(originalFs, "client"); + auto mirroredHeaders = service.InitSession(mirroredFs, "client"); + + // Create file in the original fs + service.CreateNode(originalHeaders, TCreateNodeArgs::File(RootNodeId, "testfile")); + + // Check that the file is visible in the mirrored fs + auto listNodesResponse = + service.ListNodes(mirroredHeaders, mirroredFs, RootNodeId)->Record; + UNIT_ASSERT_VALUES_EQUAL(1, listNodesResponse.NamesSize()); + UNIT_ASSERT_VALUES_EQUAL(1, listNodesResponse.NodesSize()); + UNIT_ASSERT_VALUES_EQUAL("testfile", listNodesResponse.GetNames(0)); + + auto nodeId = listNodesResponse.GetNodes(0).GetId(); + + // write to the file in the mirrored fs + auto mirroredHandle = service.CreateHandle( + mirroredHeaders, + mirroredFs, + nodeId, + "", + TCreateHandleArgs::WRNLY)->Record.GetHandle(); + auto data = GenerateValidateData(256_KB); + service.WriteData(mirroredHeaders, mirroredFs, nodeId, mirroredHandle, 0, data); + + // validate that written data can be read from the original fs + auto originalHandle = service.CreateHandle( + originalHeaders, + originalFs, + nodeId, + "", + TCreateHandleArgs::RDNLY)->Record.GetHandle(); + auto readData = service.ReadData( + originalHeaders, + originalFs, + nodeId, + originalHandle, + 0, + 256_KB)->Record.GetBuffer(); + UNIT_ASSERT_VALUES_EQUAL(data, readData); + } + + Y_UNIT_TEST(ShouldWriteCompactionMap) + { + TTestEnv env; + env.CreateSubDomain("nfs"); + + ui32 nodeIdx = env.CreateNode("nfs"); + + ui64 tabletId = -1; + ui32 lastCompactionMapRangeId = 0; + env.GetRuntime().SetEventFilter( + [&] (auto& runtime, TAutoPtr& event) { + Y_UNUSED(runtime); + switch (event->GetTypeRewrite()) { + case TEvSSProxy::EvDescribeFileStoreResponse: { + using TDesc = TEvSSProxy::TEvDescribeFileStoreResponse; + const auto* msg = event->Get(); + const auto& desc = + msg->PathDescription.GetFileStoreDescription(); + tabletId = desc.GetIndexTabletId(); + break; + } + case TEvIndexTabletPrivate:: + EvLoadCompactionMapChunkCompleted: { + lastCompactionMapRangeId = Max( + event + ->Get() + ->LastRangeId, + lastCompactionMapRangeId); + break; + } + } + + return false; + }); + + TServiceClient service(env.GetRuntime(), nodeIdx); + service.CreateFileStore("test", 1'000); + + NProtoPrivate::TWriteCompactionMapRequest request; + request.SetFileSystemId("test"); + for (ui32 i = 4; i < 30; ++i) { + NProtoPrivate::TCompactionRangeStats range; + range.SetRangeId(i); + range.SetBlobCount(1); + range.SetDeletionCount(2); + *request.AddRanges() = range; + } + + TString buf; + google::protobuf::util::MessageToJsonString(request, &buf); + auto jsonResponse = service.ExecuteAction("writecompactionmap", buf); + NProtoPrivate::TWriteCompactionMapResponse response; + UNIT_ASSERT(google::protobuf::util::JsonStringToMessage( + jsonResponse->Record.GetOutput(), + &response).ok()); + + TIndexTabletClient tablet(env.GetRuntime(), nodeIdx, tabletId); + tablet.RebootTablet(); + + UNIT_ASSERT_VALUES_EQUAL(lastCompactionMapRangeId, 29); + } } } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/service/ya.make b/cloud/filestore/libs/storage/service/ya.make index f758dd891e..c7a1b49d18 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_write_compaction_map.cpp service_actor_actions.cpp service_actor_alterfs.cpp service_actor_complete.cpp diff --git a/cloud/filestore/libs/storage/tablet/CMakeLists.darwin-x86_64.txt b/cloud/filestore/libs/storage/tablet/CMakeLists.darwin-x86_64.txt index 0b9b80ac1a..3096a07705 100644 --- a/cloud/filestore/libs/storage/tablet/CMakeLists.darwin-x86_64.txt +++ b/cloud/filestore/libs/storage/tablet/CMakeLists.darwin-x86_64.txt @@ -84,6 +84,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletecheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletegarbage.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroycheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroyhandle.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroysession.cpp @@ -121,6 +122,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writebatch.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writeblob.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writedata.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_zerorange.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_counters.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_database.cpp diff --git a/cloud/filestore/libs/storage/tablet/CMakeLists.linux-aarch64.txt b/cloud/filestore/libs/storage/tablet/CMakeLists.linux-aarch64.txt index 5b0d5904fd..064d549aa8 100644 --- a/cloud/filestore/libs/storage/tablet/CMakeLists.linux-aarch64.txt +++ b/cloud/filestore/libs/storage/tablet/CMakeLists.linux-aarch64.txt @@ -85,6 +85,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletecheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletegarbage.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroycheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroyhandle.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroysession.cpp @@ -122,6 +123,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writebatch.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writeblob.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writedata.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_zerorange.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_counters.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_database.cpp diff --git a/cloud/filestore/libs/storage/tablet/CMakeLists.linux-x86_64.txt b/cloud/filestore/libs/storage/tablet/CMakeLists.linux-x86_64.txt index 5b0d5904fd..064d549aa8 100644 --- a/cloud/filestore/libs/storage/tablet/CMakeLists.linux-x86_64.txt +++ b/cloud/filestore/libs/storage/tablet/CMakeLists.linux-x86_64.txt @@ -85,6 +85,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletecheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletegarbage.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroycheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroyhandle.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroysession.cpp @@ -122,6 +123,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writebatch.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writeblob.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writedata.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_zerorange.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_counters.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_database.cpp diff --git a/cloud/filestore/libs/storage/tablet/CMakeLists.windows-x86_64.txt b/cloud/filestore/libs/storage/tablet/CMakeLists.windows-x86_64.txt index 0b9b80ac1a..3096a07705 100644 --- a/cloud/filestore/libs/storage/tablet/CMakeLists.windows-x86_64.txt +++ b/cloud/filestore/libs/storage/tablet/CMakeLists.windows-x86_64.txt @@ -84,6 +84,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletecheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_deletegarbage.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroycheckpoint.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroyhandle.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_destroysession.cpp @@ -121,6 +122,7 @@ target_sources(libs-storage-tablet PRIVATE ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writebatch.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writeblob.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_writedata.cpp + ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_actor_zerorange.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_counters.cpp ${CMAKE_SOURCE_DIR}/cloud/filestore/libs/storage/tablet/tablet_database.cpp diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor.cpp index dee4ed0156..e1fd566d63 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor.cpp @@ -611,6 +611,11 @@ void TIndexTabletActor::HandleForcedOperation( break; } + case NProtoPrivate::TForcedOperationRequest::E_DELETE_EMPTY_RANGES: { + mode = EMode::DeleteZeroCompactionRanges; + break; + } + default: { e = MakeError(E_ARGUMENT, "unsupported mode"); } @@ -630,9 +635,19 @@ void TIndexTabletActor::HandleForcedOperation( using TResponse = TEvIndexTablet::TEvForcedOperationResponse; auto response = std::make_unique(std::move(e)); if (e.GetCode() == S_OK) { - TVector ranges = request.GetProcessAllRanges() - ? GetAllCompactionRanges() - : GetNonEmptyCompactionRanges(); + TVector ranges; + if (mode == EMode::DeleteZeroCompactionRanges) { + const auto& zeroRanges = RangesWithEmptyCompactionScore; + ui32 i = 0; + while (i < zeroRanges.size()) { + ranges.push_back(i); + i += Config->GetMaxZeroCompactionRangesToDeletePerTx(); + } + } else { + ranges = request.GetProcessAllRanges() + ? GetAllCompactionRanges() + : GetNonEmptyCompactionRanges(); + } response->Record.SetRangeCount(ranges.size()); EnqueueForcedRangeOperation(mode, std::move(ranges)); EnqueueForcedRangeOperationIfNeeded(ctx); diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor.h b/cloud/filestore/libs/storage/tablet/tablet_actor.h index 42776e7c46..9432f814ce 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor.h +++ b/cloud/filestore/libs/storage/tablet/tablet_actor.h @@ -257,6 +257,8 @@ class TIndexTabletActor final const NBlockCodecs::ICodec* BlobCodec; + TVector RangesWithEmptyCompactionScore; + public: TIndexTabletActor( const NActors::TActorId& owner, diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_compactionforced.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_compactionforced.cpp index a8c066fcf9..4b9a964446 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_compactionforced.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_compactionforced.cpp @@ -235,6 +235,16 @@ struct TCleanupRequestConstructor } }; +struct TDeleteZeroCompactionRangesRequestConstructor +{ + std::unique_ptr + operator()(const ui32 range) const + { + return std::make_unique< + TEvIndexTabletPrivate::TEvDeleteZeroCompactionRangesRequest>(range); + } +}; + using TForcedCompactionActor = TForcedOperationActor< TEvIndexTabletPrivate::TEvCompactionResponse, TCompactionRequestConstructor>; @@ -243,6 +253,10 @@ using TForcedCleanupActor = TForcedOperationActor< TEvIndexTabletPrivate::TEvCleanupResponse, TCleanupRequestConstructor>; +using TDeleteRangesWithEmptyScoreActor = TForcedOperationActor< + TEvIndexTabletPrivate::TEvDeleteZeroCompactionRangesResponse, + TDeleteZeroCompactionRangesRequestConstructor>; + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -327,6 +341,14 @@ void TIndexTabletActor::HandleForcedRangeOperation( *GetForcedRangeOperationState(), std::move(requestInfo)); break; + case TEvIndexTabletPrivate::EForcedRangeOperationMode::DeleteZeroCompactionRanges: + actor = std::make_unique( + ctx.SelfID, + LogTag, + Config->GetCompactionRetryTimeout(), + *GetForcedRangeOperationState(), + std::move(requestInfo)); + break; default: TABLET_VERIFY_C(false, "unexpected forced compaction mode"); diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp index 374fb93918..d52c85d330 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_createsession.cpp @@ -436,7 +436,19 @@ void TIndexTabletActor::CompleteTx_CreateSession( } auto* session = FindSession(args.SessionId); - TABLET_VERIFY(session); + if (!session) { + auto message = TStringBuilder() << "Session " << args.SessionId + << " destroyed during creation"; + LOG_WARN(ctx, TFileStoreComponents::TABLET, + "%s %s", + LogTag.c_str(), + message.c_str()); + + auto response = + std::make_unique(MakeError(E_REJECTED, message)); + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); + return; + } auto response = std::make_unique(args.Error); response->Record.SetSessionId(std::move(args.SessionId)); diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp new file mode 100644 index 0000000000..3b3df48ef2 --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_delete_zero_compaction_ranges.cpp @@ -0,0 +1,77 @@ +#include "tablet_actor.h" + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +using namespace NKikimr; +using namespace NKikimr::NTabletFlatExecutor; + +//////////////////////////////////////////////////////////////////////////////// + +void TIndexTabletActor::HandleDeleteZeroCompactionRanges( + const TEvIndexTabletPrivate::TEvDeleteZeroCompactionRangesRequest::TPtr& ev, + const TActorContext& ctx) +{ + auto* msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + ev->Sender, + ev->Cookie, + msg->CallContext); + + ExecuteTx( + ctx, + std::move(requestInfo), + msg->RangeId); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TIndexTabletActor::PrepareTx_DeleteZeroCompactionRanges( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TDeleteZeroCompactionRanges& args) +{ + Y_UNUSED(ctx); + Y_UNUSED(tx); + Y_UNUSED(args); + + return true; +} + +void TIndexTabletActor::ExecuteTx_DeleteZeroCompactionRanges( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TDeleteZeroCompactionRanges& args) +{ + Y_UNUSED(ctx); + + TIndexTabletDatabase db(tx.DB); + + TVector ranges( + Reserve(Config->GetMaxZeroCompactionRangesToDeletePerTx())); + ui32 rangeCount = RangesWithEmptyCompactionScore.size(); + ui32 rangesPerTx = Config->GetMaxZeroCompactionRangesToDeletePerTx(); + for (ui32 i = args.StartIndex; + i < Min(args.StartIndex + rangesPerTx, rangeCount); ++i) + { + ui32 range = RangesWithEmptyCompactionScore[i]; + db.WriteCompactionMap( + range, + GetCompactionStats(range).BlobsCount, + GetCompactionStats(range).DeletionsCount); + } + +} + +void TIndexTabletActor::CompleteTx_DeleteZeroCompactionRanges( + const TActorContext& ctx, + TTxIndexTablet::TDeleteZeroCompactionRanges& args) +{ + auto response = std::make_unique< + TEvIndexTabletPrivate::TEvDeleteZeroCompactionRangesResponse>(); + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_loadstate.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_loadstate.cpp index 83a03224cc..e5bba016c5 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_loadstate.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_loadstate.cpp @@ -464,6 +464,9 @@ void TIndexTabletActor::CompleteTx_LoadCompactionMapChunk( LoadCompactionMap(args.CompactionMap); for (const auto& x: args.CompactionMap) { args.LastRangeId = Max(args.LastRangeId, x.RangeId); + if (!x.Stats.BlobsCount && !x.Stats.DeletionsCount) { + RangesWithEmptyCompactionScore.push_back(x.RangeId); + } } using TNotification = diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_monitoring.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_monitoring.cpp index 51c19ae63f..d8a1a1f613 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_monitoring.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_monitoring.cpp @@ -251,6 +251,24 @@ void BuildForceCompactionButton(IOutputStream& out, ui64 tabletId) "Force cleanup", "Are you sure you want to force cleanup for ALL ranges?", "forceCleanupAll();"); + + out << "

Force Delete zero compaction ranges

" + << "
" + << "" + << "" + << "" + << "" + << "
"; + + BuildConfirmActionDialog( + out, + "force-delete-zero-compaction-ranges", + "Force delete zero compaction ranges", + "Are you sure you want to delete ALL zero compaction ranges?", + "forceDeleteZeroCompactionRanges();"); } //////////////////////////////////////////////////////////////////////////////// @@ -763,6 +781,14 @@ void GenerateActionsJS(IOutputStream& out) } )___"; + + out << R"___( + + )___"; } //////////////////////////////////////////////////////////////////////////////// @@ -1177,6 +1203,23 @@ void TIndexTabletActor::HandleHttpInfo_ForceOperation( return; } + TEvIndexTabletPrivate::EForcedRangeOperationMode mode; + if (params.Get("mode") == "cleanup") { + mode = TEvIndexTabletPrivate::EForcedRangeOperationMode::Cleanup; + } else if (params.Get("mode") == "compaction") { + mode = TEvIndexTabletPrivate::EForcedRangeOperationMode::Compaction; + } else if (params.Get("mode") == "deleteZeroCompactionRanges") { + mode = TEvIndexTabletPrivate::EForcedRangeOperationMode + ::DeleteZeroCompactionRanges; + } else { + RejectHttpRequest( + ctx, + TabletID(), + *requestInfo, + TStringBuilder() << "Invalid mode: " << params.Get("mode")); + return; + } + TVector ranges; if (params.Has("RangeIndex") && params.Has("RangesCount")) { ui64 rangeIndex = 0; @@ -1197,14 +1240,15 @@ void TIndexTabletActor::HandleHttpInfo_ForceOperation( rangeIndex + rangesCount, 1)); } else { - ranges = GetNonEmptyCompactionRanges(); + if (mode == TEvIndexTabletPrivate::EForcedRangeOperationMode + ::DeleteZeroCompactionRanges) + { + ranges = RangesWithEmptyCompactionScore; + } else { + ranges = GetNonEmptyCompactionRanges(); + } } - TEvIndexTabletPrivate::EForcedRangeOperationMode mode = - params.Get("mode") == "cleanup" - ? TEvIndexTabletPrivate::EForcedRangeOperationMode::Cleanup - : TEvIndexTabletPrivate::EForcedRangeOperationMode::Compaction; - EnqueueForcedRangeOperation(mode, std::move(ranges)); EnqueueForcedRangeOperationIfNeeded(ctx); diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp new file mode 100644 index 0000000000..7a0539a52c --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_write_compactionmap.cpp @@ -0,0 +1,74 @@ +#include "tablet_actor.h" + +namespace NCloud::NFileStore::NStorage { + +using namespace NActors; + +using namespace NKikimr; +using namespace NKikimr::NTabletFlatExecutor; + +//////////////////////////////////////////////////////////////////////////////// + +void TIndexTabletActor::HandleWriteCompactionMap( + const TEvIndexTablet::TEvWriteCompactionMapRequest::TPtr& ev, + const TActorContext& ctx) +{ + const auto& msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + ev->Sender, + ev->Cookie, + msg->CallContext); + + TVector ranges( + Reserve(msg->Record.GetRanges().size())); + for (const auto& range: msg->Record.GetRanges()) { + ranges.push_back(range); + } + + ExecuteTx( + ctx, + std::move(requestInfo), + std::move(ranges)); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool TIndexTabletActor::PrepareTx_WriteCompactionMap( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TWriteCompactionMap& args) +{ + Y_UNUSED(ctx); + Y_UNUSED(tx); + Y_UNUSED(args); + + return true; +} + +void TIndexTabletActor::ExecuteTx_WriteCompactionMap( + const TActorContext& ctx, + TTransactionContext& tx, + TTxIndexTablet::TWriteCompactionMap& args) +{ + Y_UNUSED(ctx); + + TIndexTabletDatabase db(tx.DB); + for (const auto& range: args.Ranges) { + db.ForceWriteCompactionMap( + range.GetRangeId(), + range.GetBlobCount(), + range.GetDeletionCount()); + } +} + +void TIndexTabletActor::CompleteTx_WriteCompactionMap( + const TActorContext& ctx, + TTxIndexTablet::TWriteCompactionMap& args) +{ + auto response = std::make_unique< + TEvIndexTablet::TEvWriteCompactionMapResponse>(); + NCloud::Reply(ctx, *args.RequestInfo, std::move(response)); +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_database.cpp b/cloud/filestore/libs/storage/tablet/tablet_database.cpp index ec8e7d58c7..c0fcfa2b7c 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_database.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_database.cpp @@ -1598,6 +1598,19 @@ bool TIndexTabletDatabase::ReadCheckpointBlobs( //////////////////////////////////////////////////////////////////////////////// // CompactionMap +void TIndexTabletDatabase::ForceWriteCompactionMap( + ui32 rangeId, + ui32 blobsCount, + ui32 deletionsCount) +{ + using TTable = TIndexTabletSchema::CompactionMap; + + Table() + .Key(rangeId) + .Update(NIceDb::TUpdate(blobsCount)) + .Update(NIceDb::TUpdate(deletionsCount)); +} + void TIndexTabletDatabase::WriteCompactionMap( ui32 rangeId, ui32 blobsCount, @@ -1606,10 +1619,7 @@ void TIndexTabletDatabase::WriteCompactionMap( using TTable = TIndexTabletSchema::CompactionMap; if (blobsCount || deletionsCount) { - Table() - .Key(rangeId) - .Update(NIceDb::TUpdate(blobsCount)) - .Update(NIceDb::TUpdate(deletionsCount)); + ForceWriteCompactionMap(rangeId, blobsCount, deletionsCount); } else { Table().Key(rangeId).Delete(); } diff --git a/cloud/filestore/libs/storage/tablet/tablet_database.h b/cloud/filestore/libs/storage/tablet/tablet_database.h index 2092879086..8bf09e056a 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_database.h +++ b/cloud/filestore/libs/storage/tablet/tablet_database.h @@ -464,6 +464,7 @@ FILESTORE_FILESYSTEM_STATS(FILESTORE_DECLARE_STATS) // CompactionMap // + void ForceWriteCompactionMap(ui32 rangeId, ui32 blobsCount, ui32 deletionsCount); void WriteCompactionMap(ui32 rangeId, ui32 blobsCount, ui32 deletionsCount); bool ReadCompactionMap(TVector& compactionMap); bool ReadCompactionMap( diff --git a/cloud/filestore/libs/storage/tablet/tablet_private.h b/cloud/filestore/libs/storage/tablet/tablet_private.h index 2c3e6ca767..9eca40bb30 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_private.h +++ b/cloud/filestore/libs/storage/tablet/tablet_private.h @@ -41,6 +41,7 @@ namespace NCloud::NFileStore::NStorage { #define FILESTORE_TABLET_REQUESTS_PRIVATE_SYNC(xxx, ...) \ xxx(AddBlob, __VA_ARGS__) \ xxx(Cleanup, __VA_ARGS__) \ + xxx(DeleteZeroCompactionRanges, __VA_ARGS__) \ xxx(DeleteGarbage, __VA_ARGS__) \ xxx(TruncateRange, __VA_ARGS__) \ xxx(ZeroRange, __VA_ARGS__) \ @@ -430,6 +431,25 @@ struct TEvIndexTabletPrivate using TCompactionCompleted = TOperationCompleted; + // + // DeleteZeroCompactionRanges + // + + struct TDeleteZeroCompactionRangesRequest + { + const ui32 RangeId; + + explicit TDeleteZeroCompactionRangesRequest(ui32 rangeId) + : RangeId(rangeId) + {} + }; + + struct TDeleteZeroCompactionRangesResponse + { + }; + + using TDeleteZeroCompactionRangesCompleted = TOperationCompleted; + // // LoadCompactionMapChunk // @@ -475,6 +495,7 @@ struct TEvIndexTabletPrivate { Compaction = 0, Cleanup = 1, + DeleteZeroCompactionRanges = 2, }; struct TForcedRangeOperationRequest diff --git a/cloud/filestore/libs/storage/tablet/tablet_tx.h b/cloud/filestore/libs/storage/tablet/tablet_tx.h index 7bebedbaf5..d88ae9c8c4 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_tx.h +++ b/cloud/filestore/libs/storage/tablet/tablet_tx.h @@ -110,6 +110,8 @@ namespace NCloud::NFileStore::NStorage { xxx(AddBlob, __VA_ARGS__) \ xxx(Cleanup, __VA_ARGS__) \ xxx(Compaction, __VA_ARGS__) \ + xxx(DeleteZeroCompactionRanges, __VA_ARGS__) \ + xxx(WriteCompactionMap, __VA_ARGS__) \ xxx(DeleteGarbage, __VA_ARGS__) \ xxx(DumpCompactionRange, __VA_ARGS__) \ xxx(FlushBytes, __VA_ARGS__) \ @@ -1643,6 +1645,48 @@ struct TTxIndexTablet } }; + // + // DeleteZeroCompactionRanges + // + + struct TDeleteZeroCompactionRanges + { + const TRequestInfoPtr RequestInfo; + const ui32 StartIndex; + + TDeleteZeroCompactionRanges( + TRequestInfoPtr requestInfo, + ui32 startIndex) + : RequestInfo(std::move(requestInfo)) + , StartIndex(startIndex) + {} + + void Clear() + { + } + }; + + // + // WriteCompactionMap + // + + struct TWriteCompactionMap + { + const TRequestInfoPtr RequestInfo; + const TVector Ranges; + + TWriteCompactionMap( + TRequestInfoPtr requestInfo, + TVector ranges) + : RequestInfo(std::move(requestInfo)) + , Ranges(std::move(ranges)) + {} + + void Clear() + { + } + }; + // // DeleteGarbage // diff --git a/cloud/filestore/libs/storage/tablet/tablet_ut_data.cpp b/cloud/filestore/libs/storage/tablet/tablet_ut_data.cpp index dd50f76e12..58769b3dd6 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_ut_data.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_ut_data.cpp @@ -3294,6 +3294,92 @@ Y_UNIT_TEST_SUITE(TIndexTabletTest_Data) } } + TABLET_TEST(ShouldDoForcedDeletionOfZeroCompactionRanges) + { + NProto::TStorageConfig storageConfig; + storageConfig.SetMaxZeroCompactionRangesToDeletePerTx(10); + + TTestEnv env({}, std::move(storageConfig)); + env.CreateSubDomain("nfs"); + + ui32 requests = 0; + ui32 lastCompactionMapRangeId = 0; + env.GetRuntime().SetEventFilter( + [&] (auto& runtime, TAutoPtr& event) + { + Y_UNUSED(runtime); + + switch (event->GetTypeRewrite()) { + case TEvIndexTabletPrivate + ::EvDeleteZeroCompactionRangesRequest: + { + ++requests; + break; + } + case TEvIndexTabletPrivate::EvLoadCompactionMapChunkCompleted: { + lastCompactionMapRangeId = Max( + event->Get< + TEvIndexTabletPrivate + ::TEvLoadCompactionMapChunkCompleted>()->LastRangeId, + lastCompactionMapRangeId); + break; + } + } + return false; + }); + + ui32 nodeIdx = env.CreateNode("nfs"); + ui64 tabletId = env.BootIndexTablet(nodeIdx); + + TIndexTabletClient tablet( + env.GetRuntime(), + nodeIdx, + tabletId, + tabletConfig); + tablet.InitSession("client", "session"); + tablet.RebootTablet(); + + TVector ranges; + for (ui32 i = 0; i < 50; ++i) { + NProtoPrivate::TCompactionRangeStats range; + range.SetRangeId(i); + range.SetBlobCount(0); + range.SetDeletionCount(0); + ranges.push_back(range); + } + for (ui32 i = 100; i < 200; ++i) { + NProtoPrivate::TCompactionRangeStats range; + range.SetRangeId(i); + range.SetBlobCount(0); + range.SetDeletionCount(0); + ranges.push_back(range); + } + for (ui32 i = 60; i < 80; ++i) { + NProtoPrivate::TCompactionRangeStats range; + range.SetRangeId(i); + range.SetBlobCount(1); + range.SetDeletionCount(2); + ranges.push_back(range); + } + tablet.WriteCompactionMap(ranges); + tablet.RebootTablet(); + + tablet.ForcedOperation( + NProtoPrivate::TForcedOperationRequest::E_DELETE_EMPTY_RANGES); + + UNIT_ASSERT_VALUES_EQUAL(requests, 15); + UNIT_ASSERT_VALUES_EQUAL(lastCompactionMapRangeId, 199); + tablet.AssertForcedRangeOperationFailed( + TVector{}, + TEvIndexTabletPrivate + ::EForcedRangeOperationMode::DeleteZeroCompactionRanges); + + lastCompactionMapRangeId = 0; + tablet.RebootTablet(); + UNIT_ASSERT_VALUES_EQUAL(lastCompactionMapRangeId, 79); + } + + TABLET_TEST(ShouldDumpCompactionRangeBlobs) { TTestEnv env; diff --git a/cloud/filestore/libs/storage/tablet/ya.make b/cloud/filestore/libs/storage/tablet/ya.make index 0c87fa96a5..1fa863c0cb 100644 --- a/cloud/filestore/libs/storage/tablet/ya.make +++ b/cloud/filestore/libs/storage/tablet/ya.make @@ -29,6 +29,7 @@ SRCS( tablet_actor_createhandle.cpp tablet_actor_createnode.cpp tablet_actor_createsession.cpp + tablet_actor_delete_zero_compaction_ranges.cpp tablet_actor_deletecheckpoint.cpp tablet_actor_deletegarbage.cpp tablet_actor_destroycheckpoint.cpp @@ -68,6 +69,7 @@ SRCS( tablet_actor_writebatch.cpp tablet_actor_writeblob.cpp tablet_actor_writedata.cpp + tablet_actor_write_compactionmap.cpp tablet_actor_zerorange.cpp tablet_counters.cpp tablet_database.cpp diff --git a/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_actor.cpp b/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_actor.cpp index 6caced6b4a..1fb842d4eb 100644 --- a/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_actor.cpp +++ b/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_actor.cpp @@ -318,7 +318,11 @@ void TIndexTabletProxyActor::HandleRequest( const auto* msg = ev->Get(); - const TString& fileSystemId = GetFileSystemId(*msg); + TString fileSystemId = GetFileSystemId(*msg); + // Some filestore names can point to another filestore, set by storage config + if (const auto* realId = Config->FindFileSystemIdByAlias(fileSystemId)) { + fileSystemId = *realId; + } TConnection& conn = CreateConnection(fileSystemId); switch (conn.State) { diff --git a/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_ut.cpp b/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_ut.cpp index 98fa3e1722..012eb58f4e 100644 --- a/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_ut.cpp +++ b/cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_ut.cpp @@ -98,6 +98,62 @@ Y_UNIT_TEST_SUITE(TIndexTabletProxyTest) env.GetRuntime().DispatchEvents({}, TDuration::MilliSeconds(100)); tabletProxy.WaitReady("test"); } + + Y_UNIT_TEST(ShouldForwardRequestsByAliases) + { + const TString originalFs = "test"; + const TString mirroredFs = "test-mirrored"; + + NProto::TStorageConfig::TFilestoreAliasEntry entry; + entry.SetAlias(mirroredFs); + entry.SetFsId(originalFs); + NProto::TStorageConfig::TFilestoreAliases aliases; + aliases.MutableEntries()->Add(std::move(entry)); + NProto::TStorageConfig storageConfig; + storageConfig.MutableFilestoreAliases()->Swap(&aliases); + + TTestEnvConfig cfg{.StaticNodes = 1, .DynamicNodes = 2}; + TTestEnv env(cfg, storageConfig); + env.CreateSubDomain("nfs"); + + auto& runtime = env.GetRuntime(); + ui32 nodeIdx = env.CreateNode("nfs"); + + TSSProxyClient ssProxy(env.GetStorageConfig(), runtime, nodeIdx); + ssProxy.CreateFileStore(originalFs, 1000); + ssProxy.CreateFileStore(mirroredFs, 1000); + + TIndexTabletProxyClient tabletProxy(env.GetRuntime(), nodeIdx); + + TVector responseTabletIds; + bool responseSent = false; + + env.GetRuntime().SetEventFilter( + [&](TTestActorRuntimeBase&, TAutoPtr& event) + { + switch (event->GetTypeRewrite()) { + case TEvService::EvListNodesResponse: { + if (!responseSent) { + responseTabletIds.push_back(event->Sender); + responseSent = true; + } + break; + } + } + + return false; + }); + + tabletProxy.SendListNodesRequest(originalFs, RootNodeId); + tabletProxy.RecvListNodesResponse(); + responseSent = false; + tabletProxy.SendListNodesRequest(mirroredFs, RootNodeId); + tabletProxy.RecvListNodesResponse(); + + // Both responses should be sent by the same actor + UNIT_ASSERT_EQUAL(responseTabletIds.size(), 2); + UNIT_ASSERT_EQUAL(responseTabletIds[0], responseTabletIds[1]); + } } } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/testlib/tablet_client.h b/cloud/filestore/libs/storage/testlib/tablet_client.h index 190dee3b85..df18676eb4 100644 --- a/cloud/filestore/libs/storage/testlib/tablet_client.h +++ b/cloud/filestore/libs/storage/testlib/tablet_client.h @@ -288,6 +288,34 @@ class TIndexTabletClient return request; } + auto CreateForcedOperationRequest( + NProtoPrivate::TForcedOperationRequest::EForcedOperationType type) + { + NProtoPrivate::TForcedOperationRequest request; + request.SetOpType(type); + auto requestToTablet = + std::make_unique(); + + requestToTablet->Record = std::move(request); + return requestToTablet; + } + + auto CreateWriteCompactionMapRequest( + const TVector& ranges) + { + NProtoPrivate::TWriteCompactionMapRequest request; + for (auto range: ranges) + { + *request.AddRanges() = range; + } + + auto requestToTablet = + std::make_unique(); + + requestToTablet->Record = std::move(request); + return requestToTablet; + } + // // TEvIndexTabletPrivate // diff --git a/cloud/filestore/libs/storage/testlib/tablet_proxy_client.h b/cloud/filestore/libs/storage/testlib/tablet_proxy_client.h index 228bbecdcd..12a968a31f 100644 --- a/cloud/filestore/libs/storage/testlib/tablet_proxy_client.h +++ b/cloud/filestore/libs/storage/testlib/tablet_proxy_client.h @@ -66,6 +66,14 @@ class TIndexTabletProxyClient return request; } + auto CreateListNodesRequest(const TString& fileSystemId, ui64 nodeId) + { + auto request = std::make_unique(); + request->Record.SetFileSystemId(fileSystemId); + request->Record.SetNodeId(nodeId); + return request; + } + #define FILESTORE_DECLARE_METHOD(name, ns) \ template \ void Send##name##Request(Args&&... args) \ diff --git a/cloud/filestore/private/api/protos/tablet.proto b/cloud/filestore/private/api/protos/tablet.proto index fe6e20c24e..556db41dd0 100644 --- a/cloud/filestore/private/api/protos/tablet.proto +++ b/cloud/filestore/private/api/protos/tablet.proto @@ -469,6 +469,7 @@ message TForcedOperationRequest { E_COMPACTION = 0; E_CLEANUP = 1; + E_DELETE_EMPTY_RANGES = 2; }; // Optional request headers. @@ -578,3 +579,18 @@ message TGetNodeAttrBatchResponse // Individual node responses. repeated NProto.TGetNodeAttrResponse Responses = 2; } + +//////////////////////////////////////////////////////////////////////////////// +// WriteCompactionMap request/response. + +message TWriteCompactionMapRequest +{ + string FileSystemId = 1; + repeated TCompactionRangeStats Ranges = 2; +} + +message TWriteCompactionMapResponse +{ + // Optional error, set only if error happened. + NCloud.NProto.TError Error = 1; +} diff --git a/cloud/storage/core/tools/ops/config_generator/main.go b/cloud/storage/core/tools/ops/config_generator/main.go index 5135d6e44a..9d0d453926 100644 --- a/cloud/storage/core/tools/ops/config_generator/main.go +++ b/cloud/storage/core/tools/ops/config_generator/main.go @@ -64,10 +64,12 @@ func getNbsConfigMap() configurator.ConfigMap { func getNfsConfigMap() configurator.ConfigMap { return configurator.ConfigMap{ - "nfs-server.txt": {Proto: &nfsProto.TServerAppConfig{}, FileName: "server.txt"}, - "nfs-storage.txt": {Proto: &nfsProto.TStorageConfig{}, FileName: "storage.txt"}, - "nfs-diag.txt": {Proto: &nfsProto.TDiagnosticsConfig{}, FileName: "diagnostics.txt"}, - "nfs-vhost.txt": {Proto: &nfsProto.TVhostAppConfig{}, FileName: "vhost.txt"}, + "nfs-server.txt": {Proto: &nfsProto.TServerAppConfig{}, FileName: "server.txt"}, + "nfs-storage.txt": {Proto: &nfsProto.TStorageConfig{}, FileName: "storage.txt"}, + "nfs-diag.txt": {Proto: &nfsProto.TDiagnosticsConfig{}, FileName: "diagnostics.txt"}, + "nfs-vhost.txt": {Proto: &nfsProto.TVhostAppConfig{}, FileName: "vhost.txt"}, + "nfs-client.txt": {Proto: &nfsProto.TClientAppConfig{}, FileName: "client.txt"}, + "nfs-features.txt": {Proto: &coreProto.TFeaturesConfig{}, FileName: "features.txt"}, // for kikimr initializer configs used custom protobuf files // from cloud/storage/core/tools/common/go/configurator/kikimr-proto