diff --git a/cloud/filestore/config/server.proto b/cloud/filestore/config/server.proto index 29cf79d0563..06ebfdfcb91 100644 --- a/cloud/filestore/config/server.proto +++ b/cloud/filestore/config/server.proto @@ -93,11 +93,17 @@ message TLocalServiceConfig // Enable Writeback cache on guest (fuse client) optional bool GuestWritebackCacheEnabled = 11; - // Async processing of destroy handle requests. + // Async processing of destroy handle requests optional bool AsyncDestroyHandleEnabled = 12; - // Period of processing create/destroy handle requests. + // Period of processing create/destroy handle requests optional uint32 AsyncHandleOperationPeriod = 13; + + // Use open_by_handle_at to lookup nodes + optional bool OpenNodeByHandleEnabled = 14; + + // Number of nodes to clean in each iteration + optional uint32 NodeCleanupBatchSize = 15; } //////////////////////////////////////////////////////////////////////////////// diff --git a/cloud/filestore/libs/service_local/config.cpp b/cloud/filestore/libs/service_local/config.cpp index 0db574f37dd..d46db3c267d 100644 --- a/cloud/filestore/libs/service_local/config.cpp +++ b/cloud/filestore/libs/service_local/config.cpp @@ -28,6 +28,8 @@ constexpr TDuration AsyncHandleOpsPeriod = TDuration::MilliSeconds(50); xxx(GuestWritebackCacheEnabled, bool, false )\ xxx(AsyncDestroyHandleEnabled, bool, false )\ xxx(AsyncHandleOperationPeriod, TDuration, AsyncHandleOpsPeriod )\ + xxx(OpenNodeByHandleEnabled, bool, false )\ + xxx(NodeCleanupBatchSize, ui32, 1000 )\ // FILESTORE_SERVICE_CONFIG #define FILESTORE_SERVICE_DECLARE_CONFIG(name, type, value) \ diff --git a/cloud/filestore/libs/service_local/config.h b/cloud/filestore/libs/service_local/config.h index 7ce3bb05f13..54d4efdfb43 100644 --- a/cloud/filestore/libs/service_local/config.h +++ b/cloud/filestore/libs/service_local/config.h @@ -32,12 +32,15 @@ class TLocalFileStoreConfig bool GetDirectIoEnabled() const; ui32 GetDirectIoAlign() const; bool GetGuestWritebackCacheEnabled() const; + ui32 GetNodeCleanupBatchSize() const; void Dump(IOutputStream& out) const; void DumpHtml(IOutputStream& out) const; bool GetAsyncDestroyHandleEnabled() const; TDuration GetAsyncHandleOperationPeriod() const; + + bool GetOpenNodeByHandleEnabled() const; }; } // namespace NCloud::NFileStore diff --git a/cloud/filestore/libs/service_local/fs_session.cpp b/cloud/filestore/libs/service_local/fs_session.cpp index e4742e9783c..2a10bd89f3b 100644 --- a/cloud/filestore/libs/service_local/fs_session.cpp +++ b/cloud/filestore/libs/service_local/fs_session.cpp @@ -72,6 +72,8 @@ NProto::TCreateSessionResponse TLocalFileSystem::CreateSession( clientId, Config->GetMaxNodeCount(), Config->GetMaxHandlePerSessionCount(), + Config->GetOpenNodeByHandleEnabled(), + Config->GetNodeCleanupBatchSize(), Logging); session->Init(request.GetRestoreClientSession()); diff --git a/cloud/filestore/libs/service_local/index.cpp b/cloud/filestore/libs/service_local/index.cpp index ded32208ff0..44dea7370ed 100644 --- a/cloud/filestore/libs/service_local/index.cpp +++ b/cloud/filestore/libs/service_local/index.cpp @@ -1,6 +1,6 @@ #include "index.h" -#include "lowlevel.h" +#include namespace NCloud::NFileStore { @@ -160,4 +160,45 @@ void TIndexNode::RemoveXAttr(const TString& name) return NLowLevel::RemoveXAttr(NodeFd, name); } +//////////////////////////////////////////////////////////////////////////////// + +TNodeLoader::TNodeLoader(const TIndexNodePtr& rootNode) + : RootHandle(rootNode->OpenHandle(O_RDONLY)) + , RootFileId(RootHandle) +{ + switch (NLowLevel::TFileId::EFileIdType(RootFileId.FileHandle.handle_type)) { + case NLowLevel::TFileId::EFileIdType::Lustre: + case NLowLevel::TFileId::EFileIdType::Weka: + break; + default: + ythrow TServiceError(E_FS_NOTSUPP) + << "Not supported hande type, RootFileId=" << RootFileId.ToString(); + } +} + +TIndexNodePtr TNodeLoader::LoadNode(ui64 nodeId) const +{ + NLowLevel::TFileId fileId(RootFileId); + + switch (NLowLevel::TFileId::EFileIdType(fileId.FileHandle.handle_type)) { + case NLowLevel::TFileId::EFileIdType::Lustre: + fileId.LustreFid.Oid = nodeId & 0xffffff; + fileId.LustreFid.Seq = (nodeId >> 24) & 0xffffffffff; + break; + case NLowLevel::TFileId::EFileIdType::Weka: + fileId.WekaInodeId.Id = nodeId; + break; + default: + ythrow TServiceError(E_FS_NOTSUPP); + } + + auto handle = fileId.Open(RootHandle, O_PATH); + return std::make_shared(nodeId, std::move(handle)); +} + +TString TNodeLoader::ToString() const +{ + return TStringBuilder() << "NodeLoader(" << RootFileId.ToString() << ")"; +} + } // namespace NCloud::NFileStore diff --git a/cloud/filestore/libs/service_local/index.h b/cloud/filestore/libs/service_local/index.h index f304a729230..6c7fd37af3d 100644 --- a/cloud/filestore/libs/service_local/index.h +++ b/cloud/filestore/libs/service_local/index.h @@ -2,6 +2,8 @@ #include "public.h" +#include "lowlevel.h" + #include #include @@ -23,6 +25,7 @@ namespace NCloud::NFileStore { class TIndexNode : private TNonCopyable + , public TIntrusiveListItem { private: const ui64 NodeId; @@ -98,6 +101,30 @@ class TIndexNode //////////////////////////////////////////////////////////////////////////////// +struct INodeLoader +{ + virtual ~INodeLoader() = default; + virtual TIndexNodePtr LoadNode(ui64 nodeId) const = 0; + virtual TString ToString() const = 0; +}; + +class TNodeLoader + : public INodeLoader +{ +private: + TFileHandle RootHandle; + NLowLevel::TFileId RootFileId; + +public: + TNodeLoader(const TIndexNodePtr& rootNode); + + [[nodiscard]] TIndexNodePtr LoadNode(ui64 nodeId) const; + + TString ToString() const; +}; + +//////////////////////////////////////////////////////////////////////////////// + class TLocalIndex { private: @@ -136,35 +163,68 @@ class TLocalIndex const TFsPath RootPath; const TFsPath StatePath; ui32 MaxNodeCount; + bool OpenNodeByHandleEnabled; + ui32 NodeCleanupBatchSize; TNodeMap Nodes; std::unique_ptr NodeTable; TRWMutex NodesLock; TLog Log; + std::shared_ptr NodeLoader; + TIntrusiveList NodeInsertOrderList; + bool ShouldCleanupNodes = false; public: TLocalIndex( TFsPath root, TFsPath statePath, ui32 maxNodeCount, - TLog log) + bool openNodeByHandleEnabled, + ui32 nodeCleanupBatchSize, + TLog log, + std::shared_ptr nodeLoader = nullptr) : RootPath(std::move(root)) , StatePath(std::move(statePath)) , MaxNodeCount(maxNodeCount) + , OpenNodeByHandleEnabled(openNodeByHandleEnabled) + , NodeCleanupBatchSize(nodeCleanupBatchSize) , Log(std::move(log)) + , NodeLoader(std::move(nodeLoader)) { Init(); } TIndexNodePtr LookupNode(ui64 nodeId) { - TReadGuard guard(NodesLock); + TReadGuard rGuard(NodesLock); + + CleanupNodesIfNeeded(); auto it = Nodes.find(nodeId); - if (it == Nodes.end()) { + if (it != Nodes.end()) { + return *it; + } + + if (!NodeLoader) { return nullptr; } - return *it; + // slow path + rGuard.Release(); + TWriteGuard wGuard(NodesLock); + + // recheck + it = Nodes.find(nodeId); + if (it != Nodes.end()) { + return *it; + } + + auto node = LoadNodeById(nodeId); + if (node) { + Nodes.insert(node); + NodeInsertOrderList.PushBack(node.get()); + } + + return node; } [[nodiscard]] bool @@ -172,6 +232,8 @@ class TLocalIndex { TWriteGuard guard(NodesLock); + CleanupNodesIfNeeded(); + auto it = Nodes.find(node->GetNodeId()); if (it != Nodes.end()) { // TODO: we can find existing node id for hard link since it has the @@ -179,24 +241,27 @@ class TLocalIndex return true; } - auto recordIndex = NodeTable->AllocRecord(); - if (recordIndex == TNodeTable::InvalidIndex) { - return false; - } + if (NodeTable) { + auto recordIndex = NodeTable->AllocRecord(); + if (recordIndex == TNodeTable::InvalidIndex) { + return false; + } - auto* record = NodeTable->RecordData(recordIndex); + auto* record = NodeTable->RecordData(recordIndex); - record->NodeId = node->GetNodeId(); - record->ParentNodeId = parentNodeId; + record->NodeId = node->GetNodeId(); + record->ParentNodeId = parentNodeId; - std::strncpy(record->Name, name.c_str(), NAME_MAX); - record->Name[NAME_MAX] = 0; + std::strncpy(record->Name, name.c_str(), NAME_MAX); + record->Name[NAME_MAX] = 0; - NodeTable->CommitRecord(recordIndex); + NodeTable->CommitRecord(recordIndex); - node->SetRecordIndex(recordIndex); - Nodes.emplace(std::move(node)); + node->SetRecordIndex(recordIndex); + } + NodeInsertOrderList.PushBack(node.get()); + Nodes.emplace(std::move(node)); return true; } @@ -204,41 +269,61 @@ class TLocalIndex { TWriteGuard guard(NodesLock); - TIndexNodePtr node = nullptr; - auto it = Nodes.find(nodeId); - if (it != Nodes.end()) { - node = *it; - NodeTable->DeleteRecord(node->GetRecordIndex()); - Nodes.erase(it); - } - - return node; + return ForgetNodeWriteLocked(nodeId); } void Clear() { TWriteGuard guard(NodesLock); - NodeTable->Clear(); + if (NodeTable) { + NodeTable->Clear(); + } + + auto it = Nodes.find(RootNodeId); + Y_ABORT_UNLESS(it != Nodes.end()); + + auto root = *it; Nodes.clear(); - Nodes.insert(TIndexNode::CreateRoot(RootPath)); + Nodes.insert(root); } private: void Init() { + auto root = TIndexNode::CreateRoot(RootPath); STORAGE_INFO( "Init index, Root=" << RootPath << - ", StatePath=" << StatePath - << ", MaxNodeCount=" << MaxNodeCount); + ", StatePath=" << StatePath << + ", MaxNodeCount=" << MaxNodeCount); + + if (OpenNodeByHandleEnabled) { + try { + if (!NodeLoader) { + NodeLoader = std::make_unique(root); + } + + STORAGE_INFO( + "Inititialize NodeLoader, Root=" << RootPath << + ", Inode=" << root->Stat().INode << + ", NodeLoader=" << NodeLoader->ToString()); + } catch (...) { + STORAGE_ERROR( + "Failed to initialize NodeLoader" << + ", Exception=" << CurrentExceptionMessage()); + } + } - Nodes.insert(TIndexNode::CreateRoot(RootPath)); + Nodes.insert(root); - NodeTable = std::make_unique( - (StatePath / "nodes").GetPath(), - MaxNodeCount); + if (!NodeLoader) { + NodeTable = std::make_unique( + (StatePath / "nodes").GetPath(), + MaxNodeCount); + + RecoverNodesFromPersistentTable(); + } - RecoverNodesFromPersistentTable(); } void RecoverNodesFromPersistentTable() @@ -313,6 +398,7 @@ class TLocalIndex auto node = TIndexNode::Create(**parentNodeIt, pathElemRecord->Name); node->SetRecordIndex(pathElemIndex); + NodeInsertOrderList.PushBack(node.get()); Nodes.insert(node); STORAGE_TRACE( @@ -342,6 +428,85 @@ class TLocalIndex { return value; } + + TIndexNodePtr LoadNodeById(ui64 nodeId) + { + try { + if (NodeLoader) { + return NodeLoader->LoadNode(nodeId); + } + } catch (...) { + } + return nullptr; + } + + // NodesLock write lock should be taken + TIndexNodePtr ForgetNodeWriteLocked(ui64 nodeId) + { + TIndexNodePtr node = nullptr; + auto it = Nodes.find(nodeId); + if (it != Nodes.end()) { + node = *it; + if (NodeTable) { + NodeTable->DeleteRecord(node->GetRecordIndex()); + } + node->TIntrusiveListItem::Unlink(); + Nodes.erase(it); + } + + return node; + } + + // called under read or write lock + template + void CleanupNodesIfNeeded() + { + // Clean nodes only if we can safely load them + if (!NodeLoader) { + return; + } + + bool isNodeLimitReached = Nodes.size() >= MaxNodeCount; + if (!isNodeLimitReached && !ShouldCleanupNodes) { + return; + } + + // slow path + + // if called under read lock upgrade it to write lock + if constexpr (std::is_same_v) { + NodesLock.ReleaseRead(); + NodesLock.AcquireWrite(); + + // recheck + isNodeLimitReached = Nodes.size() >= MaxNodeCount; + if (!isNodeLimitReached && !ShouldCleanupNodes) { + NodesLock.ReleaseWrite(); + NodesLock.AcquireRead(); + return; + } + } + + // Don't clean if nodes occupation reduced to half + ShouldCleanupNodes = Nodes.size() > (MaxNodeCount / 2); + + if (ShouldCleanupNodes) { + ui32 maxNodesToClean = isNodeLimitReached ? NodeCleanupBatchSize : 1; + auto it = NodeInsertOrderList.begin(); + while (maxNodesToClean && it != NodeInsertOrderList.end()) { + auto nodeId = it->GetNodeId(); + ++it; + --maxNodesToClean; + ForgetNodeWriteLocked(nodeId); + } + } + + // if called under read lock downgrade write lock to read lock + if constexpr (std::is_same_v) { + NodesLock.ReleaseWrite(); + NodesLock.AcquireRead(); + } + } }; } // namespace NCloud::NFileStore diff --git a/cloud/filestore/libs/service_local/index_ut.cpp b/cloud/filestore/libs/service_local/index_ut.cpp index efacb87279e..6a4e5f0b600 100644 --- a/cloud/filestore/libs/service_local/index_ut.cpp +++ b/cloud/filestore/libs/service_local/index_ut.cpp @@ -42,7 +42,7 @@ struct TEnvironment StatePath.ForceDelete(); StatePath.MkDir(); - TLocalIndex index(RootPath, StatePath, pathLen, Log); + TLocalIndex index(RootPath, StatePath, pathLen, false, 1000, Log); auto node = index.LookupNode(RootNodeId); UNIT_ASSERT_C(node, "Failed to lookup RootNode"); @@ -108,7 +108,7 @@ struct TEnvironment StatePath.ForceDelete(); StatePath.MkDir(); - TLocalIndex index(RootPath, StatePath, pathLen, Log); + TLocalIndex index(RootPath, StatePath, pathLen, false, 1000, Log); auto node = index.LookupNode(RootNodeId); UNIT_ASSERT_C(node, "Failed to lookup RootNode"); @@ -169,7 +169,7 @@ struct TEnvironment void CheckNestedDir(ui32 pathLen, const TMap& nodeMap) { - TLocalIndex index(RootPath, StatePath, pathLen, Log); + TLocalIndex index(RootPath, StatePath, pathLen, false, 1000, Log); auto node = index.LookupNode(RootNodeId); UNIT_ASSERT_C(node, "Failed to lookup root node"); @@ -197,7 +197,7 @@ struct TEnvironment void CheckMissingNodes(ui32 pathLen, const TVector& nodeIds) { - TLocalIndex index(RootPath, StatePath, pathLen, Log); + TLocalIndex index(RootPath, StatePath, pathLen, false, 1000, Log); auto node = index.LookupNode(RootNodeId); UNIT_ASSERT_C(node, "Failed to lookup root node"); @@ -221,6 +221,27 @@ struct TNodeTableRecord using TNodeTable = TPersistentTable; +struct NodeLoaderStub + : public INodeLoader +{ + + TMap NodeMap; + + TIndexNodePtr LoadNode(ui64 nodeId) const override + { + auto it = NodeMap.find(nodeId); + if (it != NodeMap.end()) { + return it->second; + } + return nullptr; + } + + TString ToString() const override + { + return "NodeLoaderStub"; + } +}; + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -278,7 +299,13 @@ Y_UNIT_TEST_SUITE(TLocalIndex) StatePath.ForceDelete(); StatePath.MkDir(); - auto index = std::make_unique(RootPath, StatePath, 100, Log); + auto index = std::make_unique( + RootPath, + StatePath, + 100, + false, + 1000, + Log); auto rootNode = index->LookupNode(RootNodeId); // create /dir1 @@ -313,7 +340,13 @@ Y_UNIT_TEST_SUITE(TLocalIndex) // delete dir3 dir3.ForceDelete(); - index = std::make_unique(RootPath, StatePath, 100, Log); + index = std::make_unique( + RootPath, + StatePath, + 100, + false, + 1000, + Log); // /dir1 and /dir2 restored UNIT_ASSERT_C(index->LookupNode(node1->GetNodeId()), @@ -331,6 +364,118 @@ Y_UNIT_TEST_SUITE(TLocalIndex) "Did not failed to lookup node id: " << node4->GetNodeId() << ", node: " << dir4.GetName()); } + + Y_UNIT_TEST_F(ShouldLoadNodes, TEnvironment) + { + RootPath.ForceDelete(); + RootPath.MkDir(); + + auto nodeLoader = std::make_shared(); + + auto index = std::make_unique( + RootPath, + StatePath, + 100, + true, // openNodeByHandleEnabled + 10, // nodeCleanupBatchSize + Log, + nodeLoader); + + auto rootNode = index->LookupNode(RootNodeId); + UNIT_ASSERT_C(rootNode, "Failed to lookup root node"); + + auto nodeAPath = RootPath / "a"; + nodeAPath.MkDir(); + auto nodeA = TIndexNode::Create(*rootNode, nodeAPath.GetName()); + UNIT_ASSERT(nodeA); + + auto node = index->LookupNode(nodeA->GetNodeId()); + UNIT_ASSERT(!node); + + nodeLoader->NodeMap.emplace(nodeA->GetNodeId(), nodeA); + node = index->LookupNode(nodeA->GetNodeId()); + UNIT_ASSERT_C(node, "failed to lookup node a"); + + } + + Y_UNIT_TEST_F(ShouldCleanupNodes, TEnvironment) + { + RootPath.ForceDelete(); + RootPath.MkDir(); + + auto nodeLoader = std::make_shared(); + + auto index = std::make_unique( + RootPath, + StatePath, + 8, + true, // openNodeByHandleEnabled + 2, // nodeCleanupBatchSize + Log, + nodeLoader); + + auto rootNode = index->LookupNode(RootNodeId); + UNIT_ASSERT_C(rootNode, "Failed to lookup root node"); + + TVector nodes; + for (ui32 i = 0; i < 10; i++) { + auto path = RootPath / ToString(i); + path.MkDir(); + auto node = TIndexNode::Create(*rootNode, path.GetName()); + UNIT_ASSERT(node); + nodes.push_back(std::move(node)); + } + + auto checkNodeInCache = [&](ui32 nodeIndex, bool isNodeInCache) { + UNIT_ASSERT_VALUES_EQUAL_C( + isNodeInCache ? 2 : 1, + nodes[nodeIndex].use_count(), + "Node #" << nodeIndex << ", NodeId=" << nodes[nodeIndex]->GetNodeId() + << (isNodeInCache ? "doesn't " : " ") << "exist in node cache"); + }; + + // fill node cache RootNode + 6 nodes = 7/8 nodes + for (ui32 i = 0; i < 6; i++) { + auto inserted = index->TryInsertNode(nodes[i], RootNodeId, ToString(i)); + UNIT_ASSERT(inserted); + } + + // check nodes in cache + for (ui32 i = 0; i < 6; i++) { + { + auto node = index->LookupNode(nodes[i]->GetNodeId()); + UNIT_ASSERT_C( + node, + "Node #" << i << ", NodeId=" << nodes[i]->GetNodeId() + << " doesn't exist in node cache"); + } + checkNodeInCache(i, true); + } + + // insert extra node cache node is full root node + 7 nodes + UNIT_ASSERT(index->TryInsertNode(nodes[6], RootNodeId, ToString(6))); + + // Trigger initial nodeCleanupBatchSize (2) nodes cleanup + UNIT_ASSERT(index->LookupNode(nodes[6]->GetNodeId())); + checkNodeInCache(0, false); + checkNodeInCache(1, false); + checkNodeInCache(2, true); + + // Trigger single node cleanup + UNIT_ASSERT(index->LookupNode(nodes[6]->GetNodeId())); + checkNodeInCache(2, false); + checkNodeInCache(3, true); + + // Trigger single node cleanup + UNIT_ASSERT(index->LookupNode(nodes[6]->GetNodeId())); + checkNodeInCache(3, false); + checkNodeInCache(4, true); + + // Node cache reduced to half of it's size no more cleanup triggered + UNIT_ASSERT(index->LookupNode(nodes[6]->GetNodeId())); + checkNodeInCache(4, true); + checkNodeInCache(5, true); + } }; } // namespace NCloud::NFileStore diff --git a/cloud/filestore/libs/service_local/lowlevel.cpp b/cloud/filestore/libs/service_local/lowlevel.cpp index 26a745aec16..3c3a3a4b315 100644 --- a/cloud/filestore/libs/service_local/lowlevel.cpp +++ b/cloud/filestore/libs/service_local/lowlevel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -621,5 +622,60 @@ UnixCredentialsGuard::~UnixCredentialsGuard() syscall(SYS_setresgid, -1, OriginalGid, -1); } +//////////////////////////////////////////////////////////////////////////////// + +TFileId::TFileId(const TFileHandle& handle) + : FileHandle{ + .handle_bytes = sizeof(Buffer), + .handle_type = 0, + .f_handle = {}, + } +{ + int mountId = 0; + int ret = + name_to_handle_at(handle, "", &FileHandle, &mountId, AT_EMPTY_PATH); + Y_ENSURE_EX( + ret != -1, + TServiceError(GetSystemErrorCode()) + << "name_to_handle_at failed: " << LastSystemErrorText()); +} + +TFileHandle TFileId::Open(const TFileHandle& mountHandle, int flags) +{ + int fd = open_by_handle_at(mountHandle, &FileHandle, flags); + Y_ENSURE_EX(fd != -1, TServiceError(GetSystemErrorCode()) + << "open_by_handle_at failed: " << LastSystemErrorText()); + return fd; +} + +TString TFileId::ToString() const +{ + TStringBuilder out; + out << "FileId[Bytes=" << FileHandle.handle_bytes + << ", Type=" << Hex(FileHandle.handle_type); + + switch (EFileIdType(FileHandle.handle_type)) { + case EFileIdType::Lustre: + out << ", Lustre(Seq=" << Hex(LustreFid.Seq) + << ", Oid=" << Hex(LustreFid.Oid) + << ", Ver=" << Hex(LustreFid.Ver) + << ", ParentSeq=" << Hex(LustreFid.ParentSeq) + << ", ParentOid=" << Hex(LustreFid.ParentOid) + << ", ParentVer=" << Hex(LustreFid.ParentVer) + << ")"; + break; + case EFileIdType::Weka: + out << ", Weka(Id=" << Hex(WekaInodeId.Id) + << ", Context=" << Hex(WekaInodeId.Context) + << ", ParentId=" << Hex(WekaInodeId.ParentId) + << ", ParentContext=" << Hex(WekaInodeId.ParentContext) + << ")"; + break; + } + + out << ", Buffer=" << HexText(TStringBuf(Buffer, FileHandle.handle_bytes)); + out << "]"; + return out; +} } // namespace NCloud::NFileStore::NLowLevel diff --git a/cloud/filestore/libs/service_local/lowlevel.h b/cloud/filestore/libs/service_local/lowlevel.h index f74f2049041..135595fec2c 100644 --- a/cloud/filestore/libs/service_local/lowlevel.h +++ b/cloud/filestore/libs/service_local/lowlevel.h @@ -26,6 +26,44 @@ class UnixCredentialsGuard { //////////////////////////////////////////////////////////////////////////////// +struct TFileId +{ + enum class EFileIdType + { + Lustre = 0x97, + Weka = 0x27 + }; + + struct file_handle FileHandle; + union { + struct + { + ui64 Seq; + ui32 Oid; + ui32 Ver; + ui64 ParentSeq; + ui32 ParentOid; + ui32 ParentVer; + } LustreFid; + struct + { + ui64 Id; + ui64 Context; + ui64 ParentId; + ui64 ParentContext; + } WekaInodeId; + char Buffer[MAX_HANDLE_SZ] = {}; + }; + + TFileId(const TFileHandle& handle); + TFileId(const TFileId& fileId) = default; + + TFileHandle Open(const TFileHandle& mountHandle, int flags); + TString ToString() const; +}; + +//////////////////////////////////////////////////////////////////////////////// + TFileHandle Open(const TString& path, int flags, int mode); TFileHandle Open(const TFileHandle& handle, int flags, int mode); TFileHandle OpenAt( diff --git a/cloud/filestore/libs/service_local/session.h b/cloud/filestore/libs/service_local/session.h index 4b5086be21a..795c841c5f8 100644 --- a/cloud/filestore/libs/service_local/session.h +++ b/cloud/filestore/libs/service_local/session.h @@ -65,18 +65,22 @@ class TSession const ui32 MaxNodeCount; const ui32 MaxHandleCount; + const bool OpenNodeByHandleEnabled; + const ui32 NodeCleanupBatchSize; TLocalIndex Index; THashMap> SubSessions; public: TSession( - const TString& fileSystemId, - const TFsPath& root, - const TFsPath& statePath, - TString clientId, - ui32 maxNodeCount, - ui32 maxHandleCount, - ILoggingServicePtr logging) + const TString& fileSystemId, + const TFsPath& root, + const TFsPath& statePath, + TString clientId, + ui32 maxNodeCount, + ui32 maxHandleCount, + bool openNodeByHandleEnabled, + ui32 nodeCleanupBatchSize, + ILoggingServicePtr logging) : RootPath(root.RealPath()) , StatePath(statePath.RealPath()) , ClientId(std::move(clientId)) @@ -84,7 +88,15 @@ class TSession , Log(Logging->CreateLog(fileSystemId + "." + ClientId)) , MaxNodeCount(maxNodeCount) , MaxHandleCount(maxHandleCount) - , Index(RootPath, StatePath, MaxNodeCount, Log) + , OpenNodeByHandleEnabled(openNodeByHandleEnabled) + , NodeCleanupBatchSize(nodeCleanupBatchSize) + , Index( + RootPath, + StatePath, + MaxNodeCount, + OpenNodeByHandleEnabled, + NodeCleanupBatchSize, + Log) {} void Init(bool restoreClientSession) @@ -113,7 +125,9 @@ class TSession ", StatePath=" << StatePath << ", SessionId=" << SessionId << ", MaxNodeCount=" << MaxNodeCount << - ", MaxHandleCount=" << MaxHandleCount); + ", MaxHandleCount=" << MaxHandleCount << + ", OpenNodeByHandleEnabled=" << OpenNodeByHandleEnabled + ); HandleTable = std::make_unique(