From 5a2bae2b50965f28b42f7b32ce03d1fafb1036a6 Mon Sep 17 00:00:00 2001 From: Maxim Deb Natkh Date: Thu, 12 Sep 2024 13:50:58 +0200 Subject: [PATCH] issue-1146: add setters for in-memory state, temporary get rid of _Ver tables (#1961) * issue-1146: add setters for in-memory state, temporary get rid of _Ver tables --- cloud/filestore/config/storage.proto | 6 +- cloud/filestore/libs/storage/core/config.cpp | 3 - cloud/filestore/libs/storage/core/config.h | 3 - .../libs/storage/tablet/tablet_database.cpp | 34 +- .../libs/storage/tablet/tablet_state.cpp | 6 +- .../storage/tablet/tablet_state_cache.cpp | 220 +++++++------ .../libs/storage/tablet/tablet_state_cache.h | 186 +++-------- .../storage/tablet/tablet_ut_state_cache.cpp | 305 ++++++++++++++++++ .../filestore/libs/storage/tablet/ut/ya.make | 1 + 9 files changed, 486 insertions(+), 278 deletions(-) create mode 100644 cloud/filestore/libs/storage/tablet/tablet_ut_state_cache.cpp diff --git a/cloud/filestore/config/storage.proto b/cloud/filestore/config/storage.proto index 888bba3d11..76ec722279 100644 --- a/cloud/filestore/config/storage.proto +++ b/cloud/filestore/config/storage.proto @@ -351,11 +351,11 @@ message TStorageConfig optional bool InMemoryIndexCacheEnabled = 371; // Capacity of in-memory index cache, in number of entries per each table optional uint64 InMemoryIndexCacheNodesCapacity = 372; - optional uint64 InMemoryIndexCacheNodesVerCapacity = 373; + reserved 373; // InMemoryIndexCacheNodesVerCapacity optional uint64 InMemoryIndexCacheNodeAttrsCapacity = 374; - optional uint64 InMemoryIndexCacheNodeAttrsVerCapacity = 375; + reserved 375; // InMemoryIndexCacheNodeAttrsVerCapacity optional uint64 InMemoryIndexCacheNodeRefsCapacity = 376; - optional uint64 InMemoryIndexCacheNodeRefsVerCapacity = 377; + reserved 377; // InMemoryIndexCacheNodeRefsVerCapacity // Used to send non-network metrics as network ones to HIVE, // while we use them for load balancing diff --git a/cloud/filestore/libs/storage/core/config.cpp b/cloud/filestore/libs/storage/core/config.cpp index 1096928e21..89aff58c48 100644 --- a/cloud/filestore/libs/storage/core/config.cpp +++ b/cloud/filestore/libs/storage/core/config.cpp @@ -193,11 +193,8 @@ using TAliases = NProto::TStorageConfig::TFilestoreAliases; \ xxx(InMemoryIndexCacheEnabled, bool, false )\ xxx(InMemoryIndexCacheNodesCapacity, ui64, 0 )\ - xxx(InMemoryIndexCacheNodesVerCapacity, ui64, 0 )\ xxx(InMemoryIndexCacheNodeAttrsCapacity, ui64, 0 )\ - xxx(InMemoryIndexCacheNodeAttrsVerCapacity, ui64, 0 )\ xxx(InMemoryIndexCacheNodeRefsCapacity, ui64, 0 )\ - xxx(InMemoryIndexCacheNodeRefsVerCapacity, ui64, 0 )\ xxx(NonNetworkMetricsBalancingFactor, ui32, 1_KB )\ \ xxx(AsyncDestroyHandleEnabled, bool, false )\ diff --git a/cloud/filestore/libs/storage/core/config.h b/cloud/filestore/libs/storage/core/config.h index 922ec0211c..96215d8567 100644 --- a/cloud/filestore/libs/storage/core/config.h +++ b/cloud/filestore/libs/storage/core/config.h @@ -228,11 +228,8 @@ class TStorageConfig bool GetInMemoryIndexCacheEnabled() const; ui64 GetInMemoryIndexCacheNodesCapacity() const; - ui64 GetInMemoryIndexCacheNodesVerCapacity() const; ui64 GetInMemoryIndexCacheNodeAttrsCapacity() const; - ui64 GetInMemoryIndexCacheNodeAttrsVerCapacity() const; ui64 GetInMemoryIndexCacheNodeRefsCapacity() const; - ui64 GetInMemoryIndexCacheNodeRefsVerCapacity() const; bool GetAsyncDestroyHandleEnabled() const; TDuration GetAsyncHandleOperationPeriod() const; diff --git a/cloud/filestore/libs/storage/tablet/tablet_database.cpp b/cloud/filestore/libs/storage/tablet/tablet_database.cpp index 1997bb0bd4..b5f5fe5979 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_database.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_database.cpp @@ -1877,16 +1877,13 @@ void TIndexTabletDatabaseProxy::WriteNodeVer( const NProto::TNode& attrs) { TIndexTabletDatabase::WriteNodeVer(nodeId, minCommitId, maxCommitId, attrs); - NodeUpdates.emplace_back(TInMemoryIndexState::TWriteNodeVerRequest{ - .NodesVerKey = {nodeId, minCommitId}, - .NodesVerRow = {.MaxCommitId = maxCommitId, .Node = attrs}}); + // TODO(#1146): _Ver tables not yet supported } void TIndexTabletDatabaseProxy::DeleteNodeVer(ui64 nodeId, ui64 commitId) { TIndexTabletDatabase::DeleteNodeVer(nodeId, commitId); - NodeUpdates.emplace_back(TInMemoryIndexState::TDeleteNodeVerRequest{ - .NodesVerKey{nodeId, commitId}}); + // TODO(#1146): _Ver tables not yet supported } void TIndexTabletDatabaseProxy::WriteNodeAttr( @@ -1906,8 +1903,8 @@ void TIndexTabletDatabaseProxy::WriteNodeAttr( void TIndexTabletDatabaseProxy::DeleteNodeAttr(ui64 nodeId, const TString& name) { TIndexTabletDatabase::DeleteNodeAttr(nodeId, name); - NodeUpdates.emplace_back(TInMemoryIndexState::TDeleteNodeAttrsRequest{ - .NodeAttrsKey = {nodeId, name}}); + NodeUpdates.emplace_back( + TInMemoryIndexState::TDeleteNodeAttrsRequest{nodeId, name}); } void TIndexTabletDatabaseProxy::WriteNodeAttrVer( @@ -1925,10 +1922,7 @@ void TIndexTabletDatabaseProxy::WriteNodeAttrVer( name, value, version); - NodeUpdates.emplace_back(TInMemoryIndexState::TWriteNodeAttrsVerRequest{ - .NodeAttrsVerKey = {nodeId, name, minCommitId}, - .NodeAttrsVerRow = - {.MaxCommitId = maxCommitId, .Value = value, .Version = version}}); + // TODO(#1146): _Ver tables not yet supported } void TIndexTabletDatabaseProxy::DeleteNodeAttrVer( @@ -1937,8 +1931,7 @@ void TIndexTabletDatabaseProxy::DeleteNodeAttrVer( const TString& name) { TIndexTabletDatabase::DeleteNodeAttrVer(nodeId, commitId, name); - NodeUpdates.emplace_back(TInMemoryIndexState::TDeleteNodeAttrsVerRequest{ - .NodeAttrsVerKey = {nodeId, name, commitId}}); + // TODO(#1146): _Ver tables not yet supported } void TIndexTabletDatabaseProxy::WriteNodeRef( @@ -1968,8 +1961,8 @@ void TIndexTabletDatabaseProxy::WriteNodeRef( void TIndexTabletDatabaseProxy::DeleteNodeRef(ui64 nodeId, const TString& name) { TIndexTabletDatabase::DeleteNodeRef(nodeId, name); - NodeUpdates.emplace_back(TInMemoryIndexState::TDeleteNodeRefsRequest{ - .NodeRefsKey = {nodeId, name}}); + NodeUpdates.emplace_back( + TInMemoryIndexState::TDeleteNodeRefsRequest{nodeId, name}); } void TIndexTabletDatabaseProxy::WriteNodeRefVer( @@ -1989,13 +1982,7 @@ void TIndexTabletDatabaseProxy::WriteNodeRefVer( childNode, followerId, followerName); - NodeUpdates.emplace_back(TInMemoryIndexState::TWriteNodeRefsVerRequest{ - .NodeRefsVerKey = {nodeId, name, minCommitId}, - .NodeRefsVerRow = { - .MaxCommitId = maxCommitId, - .ChildId = childNode, - .FollowerId = followerId, - .FollowerName = followerName}}); + // TODO(#1146): _Ver tables not yet supported } void TIndexTabletDatabaseProxy::DeleteNodeRefVer( @@ -2004,8 +1991,7 @@ void TIndexTabletDatabaseProxy::DeleteNodeRefVer( const TString& name) { TIndexTabletDatabase::DeleteNodeRefVer(nodeId, commitId, name); - NodeUpdates.emplace_back(TInMemoryIndexState::TDeleteNodeRefsVerRequest{ - .NodeRefsVerKey = {nodeId, name, commitId}}); + // TODO(#1146): _Ver tables not yet supported } } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_state.cpp b/cloud/filestore/libs/storage/tablet/tablet_state.cpp index b26f5b3676..bda81044bc 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_state.cpp @@ -124,11 +124,9 @@ void TIndexTabletState::LoadState( Impl->NodeIndexCache.Reset(config.GetNodeIndexCacheMaxNodes()); Impl->InMemoryIndexState.Reset( config.GetInMemoryIndexCacheNodesCapacity(), - config.GetInMemoryIndexCacheNodesVerCapacity(), config.GetInMemoryIndexCacheNodeAttrsCapacity(), - config.GetInMemoryIndexCacheNodeAttrsVerCapacity(), - config.GetInMemoryIndexCacheNodeRefsCapacity(), - config.GetInMemoryIndexCacheNodeRefsVerCapacity()); + config.GetInMemoryIndexCacheNodeRefsCapacity()); + for (const auto& deletionMarker: largeDeletionMarkers) { Impl->LargeBlocks.AddDeletionMarker(deletionMarker); } diff --git a/cloud/filestore/libs/storage/tablet/tablet_state_cache.cpp b/cloud/filestore/libs/storage/tablet/tablet_state_cache.cpp index 1d7bdc5edf..488c59cb9c 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state_cache.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_state_cache.cpp @@ -13,18 +13,12 @@ TInMemoryIndexState::TInMemoryIndexState(IAllocator* allocator) void TInMemoryIndexState::Reset( ui64 nodesCapacity, - ui64 nodesVerCapacity, ui64 nodeAttrsCapacity, - ui64 nodeAttrsVerCapacity, - ui64 nodeRefsCapacity, - ui64 nodeRefsVerCapacity) + ui64 nodeRefsCapacity) { NodesCapacity = nodesCapacity; - NodesVerCapacity = nodesVerCapacity; NodeAttrsCapacity = nodeAttrsCapacity; - NodeAttrsVerCapacity = nodeAttrsVerCapacity; NodeRefsCapacity = nodeRefsCapacity; - NodeRefsVerCapacity = nodeRefsVerCapacity; } // @@ -47,9 +41,29 @@ bool TInMemoryIndexState::ReadNode( if (VisibleCommitId(commitId, minCommitId, maxCommitId)) { node = TNode{nodeId, it->second.Node, minCommitId, maxCommitId}; } + + // We found the entry in table. There is at most one entry matching the key, + // meaning that cache lookup was successful, independent of whether the + // entry is visible or not to the given commitId. return true; } +void TInMemoryIndexState::WriteNode( + ui64 nodeId, + ui64 commitId, + const NProto::TNode& attrs) +{ + if (Nodes.size() == NodesCapacity && !Nodes.contains(nodeId)) { + Nodes.clear(); + } + Nodes[nodeId] = TNodeRow{.CommitId = commitId, .Node = attrs}; +} + +void TInMemoryIndexState::DeleteNode(ui64 nodeId) +{ + Nodes.erase(nodeId); +} + // // Nodes_Ver // @@ -59,30 +73,8 @@ bool TInMemoryIndexState::ReadNodeVer( ui64 commitId, TMaybe& node) { - auto it = - NodesVer.lower_bound(TNodesVerKey(nodeId, ReverseCommitId(commitId))); - if (it == NodesVer.end()) { - return false; - } - - while (it != NodesVer.end()) { - if (it->first.NodeId != nodeId) { - break; - } - - ui64 minCommitId = ReverseCommitId(it->first.MinCommitId); - ui64 maxCommitId = it->second.MaxCommitId; - - if (VisibleCommitId(commitId, minCommitId, maxCommitId)) { - node = TNode{nodeId, it->second.Node, minCommitId, maxCommitId}; - return true; - } - - ++it; - } - // Unlike TIndexTabletDatabase, if the node has not been explicitly set, - // there is no way to determine, whether the entry is present in the - // original table. + Y_UNUSED(nodeId, commitId, node); + // TODO(#1146): _Ver tables not supported yet return false; } @@ -112,10 +104,11 @@ bool TInMemoryIndexState::ReadNodeAttr( minCommitId, maxCommitId, it->second.Version}; - return true; } - - return false; + // We found the entry in table. There is at most one entry matching the key, + // meaning that cache lookup was successful, independent of whether the + // entry is visible or not to the given commitId. + return true; } bool TInMemoryIndexState::ReadNodeAttrs( @@ -129,6 +122,26 @@ bool TInMemoryIndexState::ReadNodeAttrs( return false; } +void TInMemoryIndexState::WriteNodeAttr( + ui64 nodeId, + ui64 commitId, + const TString& name, + const TString& value, + ui64 version) +{ + const auto key = TNodeAttrsKey(nodeId, name); + if (NodeAttrs.size() == NodeAttrsCapacity && !NodeAttrs.contains(key)) { + NodeAttrs.clear(); + } + NodeAttrs[key] = + TNodeAttrsRow{.CommitId = commitId, .Value = value, .Version = version}; +} + +void TInMemoryIndexState::DeleteNodeAttr(ui64 nodeId, const TString& name) +{ + NodeAttrs.erase(TNodeAttrsKey(nodeId, name)); +} + // // NodeAttrs_Ver // @@ -139,34 +152,8 @@ bool TInMemoryIndexState::ReadNodeAttrVer( const TString& name, TMaybe& attr) { - auto it = NodeAttrsVer.lower_bound( - TNodeAttrsVerKey(nodeId, name, ReverseCommitId(commitId))); - if (it == NodeAttrsVer.end()) { - return false; - } - - while (it != NodeAttrsVer.end()) { - if (it->first.NodeId != nodeId || it->first.Name != name) { - break; - } - - ui64 minCommitId = ReverseCommitId(it->first.MinCommitId); - ui64 maxCommitId = it->second.MaxCommitId; - - if (VisibleCommitId(commitId, minCommitId, maxCommitId)) { - attr = TNodeAttr{ - nodeId, - name, - it->second.Value, - minCommitId, - maxCommitId, - it->second.Version}; - return true; - } - - ++it; - } - + Y_UNUSED(nodeId, commitId, name, attr); + // TODO(#1146): _Ver tables not supported yet return false; } @@ -208,10 +195,12 @@ bool TInMemoryIndexState::ReadNodeRef( it->second.FollowerName, minCommitId, maxCommitId}; - return true; } - return false; + // We found the entry in table. There is at most one entry matching the key, + // meaning that cache lookup was successful, independent of whether the + // entry is visible or not to the given commitId. + return true; } bool TInMemoryIndexState::ReadNodeRefs( @@ -237,6 +226,30 @@ bool TInMemoryIndexState::PrechargeNodeRefs( return true; } +void TInMemoryIndexState::WriteNodeRef( + ui64 nodeId, + ui64 commitId, + const TString& name, + ui64 childNode, + const TString& followerId, + const TString& followerName) +{ + const auto key = TNodeRefsKey(nodeId, name); + if (NodeRefs.size() == NodeRefsCapacity && !NodeRefs.contains(key)) { + NodeRefs.clear(); + } + NodeRefs[key] = TNodeRefsRow{ + .CommitId = commitId, + .ChildId = childNode, + .FollowerId = followerId, + .FollowerName = followerName}; +} + +void TInMemoryIndexState::DeleteNodeRef(ui64 nodeId, const TString& name) +{ + NodeRefs.erase(TNodeRefsKey(nodeId, name)); +} + // // NodeRefs_Ver // @@ -247,35 +260,8 @@ bool TInMemoryIndexState::ReadNodeRefVer( const TString& name, TMaybe& ref) { - auto it = NodeRefsVer.lower_bound( - TNodeRefsVerKey(nodeId, name, ReverseCommitId(commitId))); - if (it == NodeRefsVer.end()) { - return false; - } - - while (it != NodeRefsVer.end()) { - if (it->first.NodeId != nodeId || it->first.Name != name) { - break; - } - - ui64 minCommitId = ReverseCommitId(it->first.MinCommitId); - ui64 maxCommitId = it->second.MaxCommitId; - - if (VisibleCommitId(commitId, minCommitId, maxCommitId)) { - ref = TNodeRef{ - nodeId, - name, - it->second.ChildId, - it->second.FollowerId, - it->second.FollowerName, - minCommitId, - maxCommitId}; - return true; - } - - ++it; - } - + Y_UNUSED(nodeId, commitId, name, ref); + // TODO(#1146): _Ver tables not supported yet return false; } @@ -305,4 +291,52 @@ bool TInMemoryIndexState::ReadCheckpointNodes( return false; } +//////////////////////////////////////////////////////////////////////////////// + +void TInMemoryIndexState::UpdateState( + const TVector& nodeUpdates) +{ + for (const auto& update: nodeUpdates) { + if (const auto* request = std::get_if(&update)) { + WriteNode( + request->NodeId, + request->Row.CommitId, + request->Row.Node); + } else if ( + const auto* request = std::get_if(&update)) + { + DeleteNode(request->NodeId); + } else if ( + const auto* request = std::get_if(&update)) + { + WriteNodeAttr( + request->NodeAttrsKey.NodeId, + request->NodeAttrsRow.CommitId, + request->NodeAttrsKey.Name, + request->NodeAttrsRow.Value, + request->NodeAttrsRow.Version); + } else if ( + const auto* request = std::get_if(&update)) + { + DeleteNodeAttr(request->NodeId, request->Name); + } else if ( + const auto* request = std::get_if(&update)) + { + WriteNodeRef( + request->NodeRefsKey.NodeId, + request->NodeRefsRow.CommitId, + request->NodeRefsKey.Name, + request->NodeRefsRow.ChildId, + request->NodeRefsRow.FollowerId, + request->NodeRefsRow.FollowerName); + } else if ( + const auto* request = std::get_if(&update)) + { + DeleteNodeRef(request->NodeId, request->Name); + } else { + Y_UNREACHABLE(); + } + } +} + } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_state_cache.h b/cloud/filestore/libs/storage/tablet/tablet_state_cache.h index 71b8462d2f..43ed69e939 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state_cache.h +++ b/cloud/filestore/libs/storage/tablet/tablet_state_cache.h @@ -21,11 +21,8 @@ class TInMemoryIndexState : public IIndexTabletDatabase void Reset( ui64 nodesCapacity, - ui64 nodesVerCapacity, ui64 nodeAttrsCapacity, - ui64 nodeAttrsVerCapacity, - ui64 nodeRefsCapacity, - ui64 nodeRefsVerCapacity); + ui64 nodeRefsCapacity); // // Nodes @@ -36,10 +33,19 @@ class TInMemoryIndexState : public IIndexTabletDatabase ui64 commitId, TMaybe& node) override; +private: + void WriteNode( + ui64 nodeId, + ui64 commitId, + const NProto::TNode& attrs); + + void DeleteNode(ui64 nodeId); + // // Nodes_Ver // +public: bool ReadNodeVer( ui64 nodeId, ui64 commitId, @@ -60,10 +66,21 @@ class TInMemoryIndexState : public IIndexTabletDatabase ui64 commitId, TVector& attrs) override; +private: + void WriteNodeAttr( + ui64 nodeId, + ui64 commitId, + const TString& name, + const TString& value, + ui64 version); + + void DeleteNodeAttr(ui64 nodeId, const TString& name); + // // NodeAttrs_Ver // +public: bool ReadNodeAttrVer( ui64 nodeId, ui64 commitId, @@ -98,10 +115,22 @@ class TInMemoryIndexState : public IIndexTabletDatabase const TString& cookie, ui32 bytesToPrecharge) override; +private: + void WriteNodeRef( + ui64 nodeId, + ui64 commitId, + const TString& name, + ui64 childNode, + const TString& followerId, + const TString& followerName); + + void DeleteNodeRef(ui64 nodeId, const TString& name); + // // NodeRefs_Ver // +public: bool ReadNodeRefVer( ui64 nodeId, ui64 commitId, @@ -125,11 +154,8 @@ class TInMemoryIndexState : public IIndexTabletDatabase private: // TODO(#1146): use LRU cache / something with better eviction policy ui64 NodesCapacity = 0; - ui64 NodesVerCapacity = 0; ui64 NodeAttrsCapacity = 0; - ui64 NodeAttrsVerCapacity = 0; ui64 NodeRefsCapacity = 0; - ui64 NodeRefsVerCapacity = 0; // // Nodes @@ -143,35 +169,6 @@ class TInMemoryIndexState : public IIndexTabletDatabase THashMap Nodes; - // - // Nodes_Ver - // - - struct TNodesVerKey - { - TNodesVerKey(ui64 nodeId, ui64 minCommitId) - : NodeId(nodeId) - , MinCommitId(minCommitId) - {} - - ui64 NodeId = 0; - ui64 MinCommitId = 0; - - bool operator<(const TNodesVerKey& rhs) const - { - return std::tie(NodeId, MinCommitId) < - std::tie(rhs.NodeId, rhs.MinCommitId); - } - }; - - struct TNodesVerRow - { - ui64 MaxCommitId = 0; - NProto::TNode Node; - }; - - TMap NodesVer; - // // NodeAttrs // @@ -209,38 +206,6 @@ class TInMemoryIndexState : public IIndexTabletDatabase THashMap NodeAttrs; - // - // NodeAttrs_Ver - // - - struct TNodeAttrsVerKey - { - TNodeAttrsVerKey(ui64 nodeId, const TString& name, ui64 minCommitId) - : NodeId(nodeId) - , Name(name) - , MinCommitId(minCommitId) - {} - - ui64 NodeId = 0; - TString Name; - ui64 MinCommitId = 0; - - bool operator<(const TNodeAttrsVerKey& rhs) const - { - return std::tie(NodeId, Name, MinCommitId) < - std::tie(rhs.NodeId, rhs.Name, rhs.MinCommitId); - } - }; - - struct TNodeAttrsVerRow - { - ui64 MaxCommitId = 0; - TString Value; - ui64 Version = 0; - }; - - TMap NodeAttrsVer; - // // NodeRefs // @@ -279,39 +244,6 @@ class TInMemoryIndexState : public IIndexTabletDatabase THashMap NodeRefs; - // - // NodeRefs_Ver - // - - struct TNodeRefsVerKey - { - TNodeRefsVerKey(ui64 nodeId, const TString& name, ui64 minCommitId) - : NodeId(nodeId) - , Name(name) - , MinCommitId(minCommitId) - {} - - ui64 NodeId = 0; - TString Name; - ui64 MinCommitId = 0; - - bool operator<(const TNodeRefsVerKey& rhs) const - { - return std::tie(NodeId, Name, MinCommitId) < - std::tie(rhs.NodeId, Name, rhs.MinCommitId); - } - }; - - struct TNodeRefsVerRow - { - ui64 MaxCommitId = 0; - ui64 ChildId = 0; - TString FollowerId; - TString FollowerName; - }; - - TMap NodeRefsVer; - public: struct TWriteNodeRequest { @@ -324,38 +256,13 @@ class TInMemoryIndexState : public IIndexTabletDatabase ui64 NodeId = 0; }; - struct TWriteNodeVerRequest - { - TNodesVerKey NodesVerKey; - TNodesVerRow NodesVerRow; - }; - - struct TDeleteNodeVerRequest - { - TNodesVerKey NodesVerKey; - }; - struct TWriteNodeAttrsRequest { TNodeAttrsKey NodeAttrsKey; TNodeAttrsRow NodeAttrsRow; }; - struct TDeleteNodeAttrsRequest - { - TNodeAttrsKey NodeAttrsKey; - }; - - struct TWriteNodeAttrsVerRequest - { - TNodeAttrsVerKey NodeAttrsVerKey; - TNodeAttrsVerRow NodeAttrsVerRow; - }; - - struct TDeleteNodeAttrsVerRequest - { - TNodeAttrsVerKey NodeAttrsVerKey; - }; + using TDeleteNodeAttrsRequest = TNodeAttrsKey; struct TWriteNodeRefsRequest { @@ -363,34 +270,17 @@ class TInMemoryIndexState : public IIndexTabletDatabase TNodeRefsRow NodeRefsRow; }; - struct TDeleteNodeRefsRequest - { - TNodeRefsKey NodeRefsKey; - }; + using TDeleteNodeRefsRequest = TNodeRefsKey; - struct TWriteNodeRefsVerRequest - { - TNodeRefsVerKey NodeRefsVerKey; - TNodeRefsVerRow NodeRefsVerRow; - }; - - struct TDeleteNodeRefsVerRequest - { - TNodeRefsVerKey NodeRefsVerKey; - }; using TIndexStateRequest = std::variant< TWriteNodeRequest, TDeleteNodeRequest, - TWriteNodeVerRequest, - TDeleteNodeVerRequest, TWriteNodeAttrsRequest, TDeleteNodeAttrsRequest, - TWriteNodeAttrsVerRequest, - TDeleteNodeAttrsVerRequest, TWriteNodeRefsRequest, - TDeleteNodeRefsRequest, - TWriteNodeRefsVerRequest, - TDeleteNodeRefsVerRequest>; + TDeleteNodeRefsRequest>; + + void UpdateState(const TVector& nodeUpdates); }; } // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/tablet_ut_state_cache.cpp b/cloud/filestore/libs/storage/tablet/tablet_ut_state_cache.cpp new file mode 100644 index 0000000000..7862567c71 --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/tablet_ut_state_cache.cpp @@ -0,0 +1,305 @@ +#include "helpers.h" +#include "tablet_state_cache.h" + +#include + +namespace NCloud::NFileStore::NStorage { + +//////////////////////////////////////////////////////////////////////////////// + +Y_UNIT_TEST_SUITE(TInMemoryIndexStateTest) +{ + const ui64 commitId1 = 1; + const ui64 commitId2 = 2; + + const ui64 nodeId1 = 101; + const ui64 nodeId2 = 102; + + const NProto::TNode nodeAttrs1 = CreateRegularAttrs(0666, 1, 2); + const NProto::TNode nodeAttrs2 = CreateRegularAttrs(0666, 3, 4); + + // + // Nodes + // + Y_UNIT_TEST(ShouldPopulateNodes) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(1, 0, 0); + + TMaybe node; + UNIT_ASSERT(!state.ReadNode(nodeId1, commitId2, node)); + + NProto::TNode realNode = nodeAttrs1; + + state.UpdateState({TInMemoryIndexState::TWriteNodeRequest{ + .NodeId = nodeId1, + .Row = { + .CommitId = commitId2, + .Node = realNode, + }}}); + + UNIT_ASSERT(state.ReadNode(nodeId1, commitId2, node)); + UNIT_ASSERT_VALUES_EQUAL(nodeId1, node->NodeId); + UNIT_ASSERT_VALUES_EQUAL( + realNode.DebugString(), + node->Attrs.DebugString()); + UNIT_ASSERT_VALUES_EQUAL(commitId2, node->MinCommitId); + UNIT_ASSERT_VALUES_EQUAL(InvalidCommitId, node->MaxCommitId); + + // Though the node is present in Nodes table, it is not visible at + // commitId1. So read from cache is considered successful, but the node + // that was read should be empty + node = {}; + UNIT_ASSERT(state.ReadNode(nodeId1, commitId1, node)); + UNIT_ASSERT(node.Empty()); + } + + Y_UNIT_TEST(ShouldEvictNodes) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(1, 0, 0); + + state.UpdateState( + {TInMemoryIndexState::TWriteNodeRequest{ + .NodeId = nodeId1, + .Row = + { + .CommitId = commitId1, + .Node = nodeAttrs1, + }}, + TInMemoryIndexState::TWriteNodeRequest{ + .NodeId = nodeId2, + .Row = { + .CommitId = commitId1, + .Node = nodeAttrs2, + }}}); + + TMaybe node; + + UNIT_ASSERT(!state.ReadNode(nodeId1, commitId1, node)); + } + + Y_UNIT_TEST(ShouldDeleteNodes) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(1, 0, 0); + + state.UpdateState({TInMemoryIndexState::TWriteNodeRequest{ + .NodeId = nodeId1, + .Row = { + .CommitId = commitId1, + .Node = nodeAttrs1, + }}}); + + TMaybe node; + UNIT_ASSERT(state.ReadNode(nodeId1, commitId1, node)); + UNIT_ASSERT(node.Defined()); + + state.UpdateState( + {TInMemoryIndexState::TDeleteNodeRequest{.NodeId = nodeId1}}); + + UNIT_ASSERT(!state.ReadNode(1, commitId1, node)); + } + + const TString attrName1 = "name1"; + const TString attrName2 = "name2"; + + const TString attrValue1 = "value1"; + const TString attrValue2 = "value2"; + + const ui64 attrVersion1 = 301; + const ui64 attrVersion2 = 302; + + // + // NodeAttrs + // + Y_UNIT_TEST(ShouldPopulateNodeAttrs) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 1, 0); + + TMaybe attr; + UNIT_ASSERT(!state.ReadNodeAttr(nodeId1, commitId2, attrName1, attr)); + + state.UpdateState({TInMemoryIndexState::TWriteNodeAttrsRequest{ + .NodeAttrsKey = + { + nodeId1, + attrName1, + }, + .NodeAttrsRow = { + commitId2, + attrValue1, + attrVersion1, + }}}); + + UNIT_ASSERT(state.ReadNodeAttr(nodeId1, commitId2, attrName1, attr)); + UNIT_ASSERT_VALUES_EQUAL(nodeId1, attr->NodeId); + UNIT_ASSERT_VALUES_EQUAL(attrName1, attr->Name); + UNIT_ASSERT_VALUES_EQUAL(attrValue1, attr->Value); + UNIT_ASSERT_VALUES_EQUAL(commitId2, attr->MinCommitId); + UNIT_ASSERT_VALUES_EQUAL(InvalidCommitId, attr->MaxCommitId); + UNIT_ASSERT_VALUES_EQUAL(attrVersion1, attr->Version); + + // Though the node is present in NodeAttrs table, it is not visible at + // commitId1. So read from cache is considered successful, but the node + // that was read should be empty + attr = {}; + UNIT_ASSERT(state.ReadNodeAttr(nodeId1, commitId1, attrName1, attr)); + UNIT_ASSERT(attr.Empty()); + } + + Y_UNIT_TEST(ShouldEvictNodeAttrs) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 1, 0); + + state.UpdateState( + {TInMemoryIndexState::TWriteNodeAttrsRequest{ + .NodeAttrsKey = {nodeId1, attrName1}, + .NodeAttrsRow = {commitId1, attrValue1, attrVersion1}, + }, + TInMemoryIndexState::TWriteNodeAttrsRequest{ + .NodeAttrsKey = {nodeId2, attrName2}, + .NodeAttrsRow = {commitId1, attrValue2, attrVersion2}, + }}); + + TMaybe attr; + + UNIT_ASSERT(!state.ReadNodeAttr(nodeId1, commitId1, attrName1, attr)); + } + + Y_UNIT_TEST(ShouldDeleteNodeAttrs) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 1, 0); + + state.UpdateState({TInMemoryIndexState::TWriteNodeAttrsRequest{ + .NodeAttrsKey = {nodeId1, attrName1}, + .NodeAttrsRow = {commitId1, attrValue1, attrVersion1}, + }}); + + TMaybe attr; + UNIT_ASSERT(state.ReadNodeAttr(nodeId1, commitId1, attrName1, attr)); + UNIT_ASSERT(attr.Defined()); + + state.UpdateState( + {TInMemoryIndexState::TDeleteNodeAttrsRequest{nodeId1, attrName1}}); + + UNIT_ASSERT(!state.ReadNodeAttr(nodeId1, commitId1, attrName1, attr)); + } + + const TString nodeName1 = "node1"; + const TString nodeName2 = "node2"; + const TString followerName1 = "follower1"; + const TString followerName2 = "follower2"; + const TString followerId1 = "followerId1"; + const TString followerId2 = "followerId2"; + + // + // NodeRefs + // + Y_UNIT_TEST(ShoulPopulateNodeRefs) + { + // For now + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 0, 1); + + TMaybe ref; + UNIT_ASSERT(!state.ReadNodeRef(nodeId1, commitId2, nodeName1, ref)); + + state.UpdateState({TInMemoryIndexState::TWriteNodeRefsRequest{ + .NodeRefsKey = {RootNodeId, nodeName1}, + .NodeRefsRow = { + .CommitId = commitId2, + .ChildId = nodeId1, + .FollowerId = followerId1, + .FollowerName = followerName1}}}); + + UNIT_ASSERT(state.ReadNodeRef(RootNodeId, commitId2, nodeName1, ref)); + UNIT_ASSERT_VALUES_EQUAL(RootNodeId, ref->NodeId); + UNIT_ASSERT_VALUES_EQUAL(nodeName1, ref->Name); + UNIT_ASSERT_VALUES_EQUAL(nodeId1, ref->ChildNodeId); + UNIT_ASSERT_VALUES_EQUAL(commitId2, ref->MinCommitId); + UNIT_ASSERT_VALUES_EQUAL(InvalidCommitId, ref->MaxCommitId); + UNIT_ASSERT_VALUES_EQUAL(followerId1, ref->FollowerId); + UNIT_ASSERT_VALUES_EQUAL(followerName1, ref->FollowerName); + + // The cache is preemptive, so the listing should not be possible for + // now + TVector refs; + TString next; + UNIT_ASSERT(!state.ReadNodeRefs( + RootNodeId, + commitId2, + "", + refs, + Max(), + &next)); + UNIT_ASSERT(refs.empty()); + UNIT_ASSERT(next.Empty()); + + // Though the node is present in NodeRefs table, it is not visible at + // commitId1. So read from cache is considered successful, but the node + // that was read should be empty + ref = {}; + UNIT_ASSERT(state.ReadNodeRef(RootNodeId, commitId1, nodeName1, ref)); + UNIT_ASSERT(ref.Empty()); + } + + Y_UNIT_TEST(ShouldEvictNodeRefs) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 0, 1); + + state.UpdateState( + {TInMemoryIndexState::TWriteNodeRefsRequest{ + .NodeRefsKey = {RootNodeId, nodeName1}, + .NodeRefsRow = + { + .CommitId = commitId1, + .ChildId = nodeId1, + .FollowerId = followerId1, + .FollowerName = followerName1, + }}, + TInMemoryIndexState::TWriteNodeRefsRequest{ + .NodeRefsKey = {RootNodeId, nodeName2}, + .NodeRefsRow = { + .CommitId = commitId1, + .ChildId = nodeId2, + .FollowerId = followerId2, + .FollowerName = followerName2, + }}}); + + TMaybe ref; + + UNIT_ASSERT(!state.ReadNodeRef(RootNodeId, commitId1, nodeName1, ref)); + } + + Y_UNIT_TEST(ShouldDeleteNodeRefs) + { + TInMemoryIndexState state(TDefaultAllocator::Instance()); + state.Reset(0, 0, 1); + + state.UpdateState({TInMemoryIndexState::TWriteNodeRefsRequest{ + .NodeRefsKey = {RootNodeId, nodeName1}, + .NodeRefsRow = { + .CommitId = commitId1, + .ChildId = nodeId1, + .FollowerId = followerId1, + .FollowerName = followerName1, + }}}); + + TMaybe ref; + UNIT_ASSERT(state.ReadNodeRef(RootNodeId, commitId1, nodeName1, ref)); + UNIT_ASSERT(ref.Defined()); + + state.UpdateState({TInMemoryIndexState::TDeleteNodeRefsRequest{ + RootNodeId, + nodeName1}}); + + UNIT_ASSERT(!state.ReadNodeRef(RootNodeId, commitId1, nodeName1, ref)); + } +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/ut/ya.make b/cloud/filestore/libs/storage/tablet/ut/ya.make index 95d8263f4d..e099d0f904 100644 --- a/cloud/filestore/libs/storage/tablet/ut/ya.make +++ b/cloud/filestore/libs/storage/tablet/ut/ya.make @@ -21,6 +21,7 @@ SRCS( tablet_ut_sessions.cpp tablet_ut_subsessions.cpp tablet_ut_throttling.cpp + tablet_ut_state_cache.cpp ) PEERDIR(