Skip to content

Commit

Permalink
issue-1794: support aliases for filestore names (#1774)
Browse files Browse the repository at this point in the history
* issue-1794: support aliases for filestore names
  • Loading branch information
debnatkh committed Aug 18, 2024
1 parent 52a96ba commit 6d00c74
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 2 deletions.
12 changes: 12 additions & 0 deletions cloud/filestore/config/storage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,16 @@ message TStorageConfig

// 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;
}
55 changes: 55 additions & 0 deletions cloud/filestore/libs/storage/core/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <library/cpp/monlib/service/pages/templates.h>

#include <util/generic/hash.h>
#include <util/generic/size_literals.h>

#include <google/protobuf/text_format.h>
Expand All @@ -12,6 +13,10 @@ namespace {

////////////////////////////////////////////////////////////////////////////////

// Type alias is used here because using THashMap<TString, TString> inside macro
// will mess it up because of the comma in the type.
using TAliasMap = THashMap<TString, TString>;

#define FILESTORE_STORAGE_CONFIG(xxx) \
xxx(SchemeShardDir, TString, "/Root" )\
\
Expand Down Expand Up @@ -169,6 +174,8 @@ namespace {
xxx(BlobCompressionRate, ui32, 0 )\
xxx(BlobCompressionCodec, TString, "lz4" )\
\
xxx(FilestoreAliases, TAliasMap, {} )\
\
xxx(MaxZeroCompactionRangesToDeletePerTx, ui32, 10000 )\
// FILESTORE_STORAGE_CONFIG

Expand All @@ -188,12 +195,40 @@ bool IsEmpty(const T& t)
return !t;
}

template <>
bool IsEmpty(const NCloud::NProto::TCertificate& value)
{
return !value.GetCertFile() && !value.GetCertPrivateKeyFile();
}

template <>
bool IsEmpty(const NProto::TStorageConfig::TFilestoreAliases& value)
{
return value.GetEntries().empty();
}

template <typename TTarget, typename TSource>
TTarget ConvertValue(const TSource& value)
{
return static_cast<TTarget>(value);
}

template <>
TCertificate ConvertValue(const NCloud::NProto::TCertificate& value)
{
return {value.GetCertFile(), value.GetCertPrivateKeyFile()};
}

template <>
TAliasMap ConvertValue(const NProto::TStorageConfig::TFilestoreAliases& value)
{
TAliasMap result;
for (const auto& entry: value.GetEntries()) {
result[entry.GetAlias()] = entry.GetFsId();
}
return result;
}

template <>
TDuration ConvertValue<TDuration, ui32>(const ui32& value)
{
Expand All @@ -220,6 +255,26 @@ void DumpImpl(const T& t, IOutputStream& os)
os << t;
}

template <>
void DumpImpl(const TCertificate& value, IOutputStream& os)
{
os << "{ "
<< value.CertFile
<< ", "
<< value.CertPrivateKeyFile
<< " }";
}

template <>
void DumpImpl(const TAliasMap& value, IOutputStream& os)
{
os << "{ ";
for (const auto& [alias, fsId]: value) {
os << alias << ": " << fsId << ", ";
}
os << " }";
}

} // namespace

////////////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 2 additions & 0 deletions cloud/filestore/libs/storage/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ class TStorageConfig
TString GetBlobCompressionCodec() const;

const NProto::TStorageConfig& GetStorageConfigProto() const;

THashMap<TString, TString> GetFilestoreAliases() const;
};

} // namespace NCloud::NFileStore::NStorage
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,11 @@ 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();
auto it = StorageConfig->GetFilestoreAliases().find(fileSystemId);
if (it != StorageConfig->GetFilestoreAliases().end()) {
fileSystemId = it->second;
}
const auto& checkpointId = msg->Record.GetCheckpointId();
auto originFqdn = GetOriginFqdn(msg->Record);

Expand Down
66 changes: 66 additions & 0 deletions cloud/filestore/libs/storage/service/service_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5213,6 +5213,72 @@ 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,12 @@ 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
auto it = Config->GetFilestoreAliases().find(fileSystemId);
if (it != Config->GetFilestoreAliases().end()) {
fileSystemId = it->second;
}

TConnection& conn = CreateConnection(fileSystemId);
switch (conn.State) {
Expand Down
56 changes: 56 additions & 0 deletions cloud/filestore/libs/storage/tablet_proxy/tablet_proxy_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TActorId> responseTabletIds;
bool responseSent = false;

env.GetRuntime().SetEventFilter(
[&](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& 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
8 changes: 8 additions & 0 deletions cloud/filestore/libs/storage/testlib/tablet_proxy_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ class TIndexTabletProxyClient
return request;
}

auto CreateListNodesRequest(const TString& fileSystemId, ui64 nodeId)
{
auto request = std::make_unique<TEvService::TEvListNodesRequest>();
request->Record.SetFileSystemId(fileSystemId);
request->Record.SetNodeId(nodeId);
return request;
}

#define FILESTORE_DECLARE_METHOD(name, ns) \
template <typename... Args> \
void Send##name##Request(Args&&... args) \
Expand Down

0 comments on commit 6d00c74

Please sign in to comment.