From 3af09640ac04476c4b852eeb1f3932a7774a723b Mon Sep 17 00:00:00 2001 From: proller Date: Sat, 31 Aug 2024 18:06:34 +0200 Subject: [PATCH] Stat about opened files from one/many sessions (#1818) * Stat about opened files from one/many sessions * Style * style * simpler * Names * Simpler * Simpler * Simpler * clean * fixes * safe * fixes * Some fixes * better * better * better * better * test name * move * clean * Add test --- .../tablet/model/node_session_stat.cpp | 98 +++++++++++++ .../storage/tablet/model/node_session_stat.h | 43 ++++++ .../tablet/model/node_session_stat_ut.cpp | 98 +++++++++++++ .../libs/storage/tablet/model/ut/ya.make | 1 + .../libs/storage/tablet/model/ya.make | 1 + .../libs/storage/tablet/tablet_actor.h | 8 +- .../storage/tablet/tablet_actor_counters.cpp | 35 ++++- .../libs/storage/tablet/tablet_state.h | 17 +++ .../libs/storage/tablet/tablet_state_impl.h | 2 + .../storage/tablet/tablet_state_sessions.cpp | 64 +++++++++ .../libs/storage/tablet/tablet_ut_nodes.cpp | 135 ++++++++++++++++++ 11 files changed, 498 insertions(+), 4 deletions(-) create mode 100644 cloud/filestore/libs/storage/tablet/model/node_session_stat.cpp create mode 100644 cloud/filestore/libs/storage/tablet/model/node_session_stat.h create mode 100644 cloud/filestore/libs/storage/tablet/model/node_session_stat_ut.cpp diff --git a/cloud/filestore/libs/storage/tablet/model/node_session_stat.cpp b/cloud/filestore/libs/storage/tablet/model/node_session_stat.cpp new file mode 100644 index 00000000000..12a42227ff6 --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/model/node_session_stat.cpp @@ -0,0 +1,98 @@ +#include "node_session_stat.h" + +namespace NCloud::NFileStore::NStorage { + +TNodeToSessionStat::EKind TNodeToSessionStat::AddRead( + ui64 nodeId, + const TString& sessionId) +{ + ++Stat[nodeId].ReadSessions[sessionId]; + return GetKind(nodeId); +} + +TNodeToSessionStat::EKind TNodeToSessionStat::AddWrite( + ui64 nodeId, + const TString& sessionId) +{ + ++Stat[nodeId].WriteSessions[sessionId]; + return GetKind(nodeId); +} + +void TNodeToSessionStat::Clean( + const TStat::iterator& nodeStatIterator, + const TString& sessionId) +{ + auto& nodeStat = nodeStatIterator->second; + + { + const auto it = nodeStat.WriteSessions.find(sessionId); + if (it != nodeStat.WriteSessions.end() && it->second <= 0) { + nodeStat.WriteSessions.erase(it); + } + } + + { + const auto it = nodeStat.ReadSessions.find(sessionId); + if (it != nodeStat.ReadSessions.end() && it->second <= 0) { + nodeStat.ReadSessions.erase(it); + } + } + + if (nodeStat.WriteSessions.empty() && nodeStat.ReadSessions.empty()) { + Stat.erase(nodeStatIterator); + } +} + +TNodeToSessionStat::EKind TNodeToSessionStat::RemoveRead( + ui64 nodeId, + const TString& sessionId) +{ + const auto& nodeStatIterator = Stat.find(nodeId); + if (nodeStatIterator != Stat.end()) { + --nodeStatIterator->second.ReadSessions[sessionId]; + Clean(nodeStatIterator, sessionId); + } + return GetKind(nodeStatIterator); +} + +TNodeToSessionStat::EKind TNodeToSessionStat::RemoveWrite( + ui64 nodeId, + const TString& sessionId) +{ + const auto& nodeStatIterator = Stat.find(nodeId); + if (nodeStatIterator != Stat.end()) { + --nodeStatIterator->second.WriteSessions[sessionId]; + Clean(nodeStatIterator, sessionId); + } + return GetKind(nodeStatIterator); +} + +TNodeToSessionStat::EKind TNodeToSessionStat::GetKind(ui64 nodeId) const +{ + const auto& nodeStatIterator = Stat.find(nodeId); + return GetKind(nodeStatIterator); +} + +TNodeToSessionStat::EKind TNodeToSessionStat::GetKind( + const TStat::const_iterator& nodeStatIterator) const +{ + if (nodeStatIterator == Stat.end()) { + return EKind::None; + } + const auto& nodeStat = nodeStatIterator->second; + if (nodeStat.WriteSessions.size() > 1) { + return EKind::NodesOpenForWritingByMultipleSessions; + } + if (nodeStat.WriteSessions.size() == 1) { + return EKind::NodesOpenForWritingBySingleSession; + } + if (nodeStat.ReadSessions.size() > 1) { + return EKind::NodesOpenForReadingByMultipleSessions; + } + if (nodeStat.ReadSessions.size() == 1) { + return EKind::NodesOpenForReadingBySingleSession; + } + return EKind::None; +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/model/node_session_stat.h b/cloud/filestore/libs/storage/tablet/model/node_session_stat.h new file mode 100644 index 00000000000..39b323fca41 --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/model/node_session_stat.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace NCloud::NFileStore::NStorage { + +class TNodeToSessionStat +{ + struct TSessionStat + { + THashMap ReadSessions; + THashMap WriteSessions; + }; + using TStat = THashMap; + TStat Stat; + + void Clean( + const TStat::iterator& nodeStatIterator, + const TString& sessionId); + +public: + enum class EKind + { + None, + NodesOpenForWritingBySingleSession, + NodesOpenForWritingByMultipleSessions, + NodesOpenForReadingBySingleSession, + NodesOpenForReadingByMultipleSessions, + }; + + EKind AddRead(ui64 nodeId, const TString& sessionId); + EKind AddWrite(ui64 nodeId, const TString& sessionId); + EKind RemoveRead(ui64 nodeId, const TString& sessionId); + EKind RemoveWrite(ui64 nodeId, const TString& sessionId); + [[nodiscard]] EKind GetKind(ui64 nodeId) const; + +private: + [[nodiscard]] EKind GetKind( + const TStat::const_iterator& nodeStatIterator) const; +}; + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/model/node_session_stat_ut.cpp b/cloud/filestore/libs/storage/tablet/model/node_session_stat_ut.cpp new file mode 100644 index 00000000000..e0b6dc55e3d --- /dev/null +++ b/cloud/filestore/libs/storage/tablet/model/node_session_stat_ut.cpp @@ -0,0 +1,98 @@ +#include "node_session_stat.h" + +#include + +namespace NCloud::NFileStore::NStorage { + +//////////////////////////////////////////////////////////////////////////////// + +Y_UNIT_TEST_SUITE(TNodeToSessionStat) +{ + Y_UNIT_TEST(ShouldStat) + { + TNodeToSessionStat nodeToSessionStat; + const ui64 nodeId1 = 1; + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.GetKind(nodeId1), + TNodeToSessionStat::EKind::None); + + TString sessionId1 = "1"; + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddRead(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForReadingBySingleSession); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddRead(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForReadingBySingleSession); + + TString sessionId2 = "2"; + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddRead(nodeId1, sessionId2), + TNodeToSessionStat::EKind::NodesOpenForReadingByMultipleSessions); + + TString sessionId3 = "3"; + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddWrite(nodeId1, sessionId3), + TNodeToSessionStat::EKind::NodesOpenForWritingBySingleSession); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddWrite(nodeId1, sessionId2), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveRead(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + const ui64 nodeId2 = 2; + UNIT_ASSERT_EQUAL( + nodeToSessionStat.AddWrite(nodeId2, sessionId2), + TNodeToSessionStat::EKind::NodesOpenForWritingBySingleSession); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.GetKind(nodeId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId2, sessionId2), + TNodeToSessionStat::EKind::None); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.GetKind(nodeId1), + TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId1, sessionId2), + TNodeToSessionStat::EKind::NodesOpenForWritingBySingleSession); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveWrite(nodeId1, sessionId3), + TNodeToSessionStat::EKind::NodesOpenForReadingByMultipleSessions); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveRead(nodeId1, sessionId1), + TNodeToSessionStat::EKind::NodesOpenForReadingBySingleSession); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveRead(nodeId1, sessionId2), + TNodeToSessionStat::EKind::None); + + UNIT_ASSERT_EQUAL( + nodeToSessionStat.RemoveRead(nodeId1, sessionId1), + TNodeToSessionStat::EKind::None); + } +} + +} // namespace NCloud::NFileStore::NStorage diff --git a/cloud/filestore/libs/storage/tablet/model/ut/ya.make b/cloud/filestore/libs/storage/tablet/model/ut/ya.make index 24846d5669f..e9f6332b384 100644 --- a/cloud/filestore/libs/storage/tablet/model/ut/ya.make +++ b/cloud/filestore/libs/storage/tablet/model/ut/ya.make @@ -12,6 +12,7 @@ SRCS( garbage_queue_ut.cpp mixed_blocks_ut.cpp node_index_cache_ut.cpp + node_session_stat_ut.cpp operation_ut.cpp range_locks_ut.cpp read_ahead_ut.cpp diff --git a/cloud/filestore/libs/storage/tablet/model/ya.make b/cloud/filestore/libs/storage/tablet/model/ya.make index 444c99d3d9d..9967a6b3890 100644 --- a/cloud/filestore/libs/storage/tablet/model/ya.make +++ b/cloud/filestore/libs/storage/tablet/model/ya.make @@ -25,6 +25,7 @@ SRCS( group_by.cpp mixed_blocks.cpp node_index_cache.cpp + node_session_stat.cpp operation.cpp range_locks.cpp read_ahead.cpp diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor.h b/cloud/filestore/libs/storage/tablet/tablet_actor.h index c4213c743b6..d8b48bf48d3 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor.h +++ b/cloud/filestore/libs/storage/tablet/tablet_actor.h @@ -137,6 +137,11 @@ class TIndexTabletActor final std::atomic UncompressedBytesWritten{0}; std::atomic CompressedBytesWritten{0}; + std::atomic NodesOpenForWritingBySingleSession{0}; + std::atomic NodesOpenForWritingByMultipleSessions{0}; + std::atomic NodesOpenForReadingBySingleSession{0}; + std::atomic NodesOpenForReadingByMultipleSessions{0}; + NMetrics::TDefaultWindowCalculator MaxUsedQuota{0}; using TLatHistogram = NMetrics::THistogram; @@ -201,7 +206,8 @@ class TIndexTabletActor final const TSessionsStats& sessionsStats, const TChannelsStats& channelsStats, const TReadAheadCacheStats& readAheadStats, - const TNodeIndexCacheStats& nodeIndexCacheStats); + const TNodeIndexCacheStats& nodeIndexCacheStats, + const TNodeToSessionCounters& nodeToSessionCounters); } Metrics; const IProfileLogPtr ProfileLog; diff --git a/cloud/filestore/libs/storage/tablet/tablet_actor_counters.cpp b/cloud/filestore/libs/storage/tablet/tablet_actor_counters.cpp index a3448d58264..2571fb6d001 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_actor_counters.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_actor_counters.cpp @@ -297,6 +297,19 @@ void TIndexTabletActor::TMetrics::Register( REGISTER_AGGREGATABLE_SUM(AllocatedCompactionRangesCount, EMetricType::MT_ABSOLUTE); REGISTER_AGGREGATABLE_SUM(UsedCompactionRangesCount, EMetricType::MT_ABSOLUTE); + REGISTER_AGGREGATABLE_SUM( + NodesOpenForWritingBySingleSession, + EMetricType::MT_ABSOLUTE); + REGISTER_AGGREGATABLE_SUM( + NodesOpenForWritingByMultipleSessions, + EMetricType::MT_ABSOLUTE); + REGISTER_AGGREGATABLE_SUM( + NodesOpenForReadingBySingleSession, + EMetricType::MT_ABSOLUTE); + REGISTER_AGGREGATABLE_SUM( + NodesOpenForReadingByMultipleSessions, + EMetricType::MT_ABSOLUTE); + // Throttling REGISTER_LOCAL(MaxReadBandwidth, EMetricType::MT_ABSOLUTE); REGISTER_LOCAL(MaxWriteBandwidth, EMetricType::MT_ABSOLUTE); @@ -374,7 +387,8 @@ void TIndexTabletActor::TMetrics::Update( const TSessionsStats& sessionsStats, const TChannelsStats& channelsStats, const TReadAheadCacheStats& readAheadStats, - const TNodeIndexCacheStats& nodeIndexCacheStats) + const TNodeIndexCacheStats& nodeIndexCacheStats, + const TNodeToSessionCounters& nodeToSessionCounters) { const ui32 blockSize = fileSystem.GetBlockSize(); @@ -432,6 +446,19 @@ void TIndexTabletActor::TMetrics::Update( Store(ReadAheadCacheNodeCount, readAheadStats.NodeCount); Store(NodeIndexCacheNodeCount, nodeIndexCacheStats.NodeCount); + Store( + NodesOpenForWritingBySingleSession, + nodeToSessionCounters.NodesOpenForWritingBySingleSession); + Store( + NodesOpenForWritingByMultipleSessions, + nodeToSessionCounters.NodesOpenForWritingByMultipleSessions); + Store( + NodesOpenForReadingBySingleSession, + nodeToSessionCounters.NodesOpenForReadingBySingleSession); + Store( + NodesOpenForReadingByMultipleSessions, + nodeToSessionCounters.NodesOpenForReadingByMultipleSessions); + BusyIdleCalc.OnUpdateStats(); } @@ -479,7 +506,8 @@ void TIndexTabletActor::RegisterStatCounters() CalculateSessionsStats(), CalculateChannelsStats(), CalculateReadAheadCacheStats(), - CalculateNodeIndexCacheStats()); + CalculateNodeIndexCacheStats(), + GetNodeToSessionCounters()); Metrics.Register(fsId, storageMediaKind); } @@ -524,7 +552,8 @@ void TIndexTabletActor::HandleUpdateCounters( CalculateSessionsStats(), CalculateChannelsStats(), CalculateReadAheadCacheStats(), - CalculateNodeIndexCacheStats()); + CalculateNodeIndexCacheStats(), + GetNodeToSessionCounters()); SendMetricsToExecutor(ctx); UpdateCountersScheduled = false; diff --git a/cloud/filestore/libs/storage/tablet/tablet_state.h b/cloud/filestore/libs/storage/tablet/tablet_state.h index 691226a1b8e..89cbea8b03b 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state.h +++ b/cloud/filestore/libs/storage/tablet/tablet_state.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,14 @@ struct TFlushBytesStats bool ChunkCompleted = false; }; +struct TNodeToSessionCounters +{ + i64 NodesOpenForWritingBySingleSession{0}; + i64 NodesOpenForWritingByMultipleSessions{0}; + i64 NodesOpenForReadingBySingleSession{0}; + i64 NodesOpenForReadingByMultipleSessions{0}; +}; + //////////////////////////////////////////////////////////////////////////////// class TIndexTabletState @@ -140,6 +149,7 @@ class TIndexTabletState NProto::TFileSystem FileSystem; NProto::TFileSystemStats FileSystemStats; NCloud::NProto::TTabletStorageInfo TabletStorageInfo; + TNodeToSessionCounters NodeToSessionCounters; /*const*/ ui32 TruncateBlocksThreshold = 0; /*const*/ ui32 SessionHistoryEntryCount = 0; @@ -243,6 +253,11 @@ class TIndexTabletState return FileSystemStats; } + const TNodeToSessionCounters& GetNodeToSessionCounters() const + { + return NodeToSessionCounters; + } + const NProto::TFileStorePerformanceProfile& GetPerformanceProfile() const; const TFileStoreAllocRegistry& GetFileStoreProfilingRegistry() const @@ -294,6 +309,8 @@ FILESTORE_FILESYSTEM_STATS(FILESTORE_DECLARE_COUNTER) #undef FILESTORE_DECLARE_COUNTER + void ChangeNodeCounters(const TNodeToSessionStat::EKind nodeKind, i64 amount); + // // Throttling // diff --git a/cloud/filestore/libs/storage/tablet/tablet_state_impl.h b/cloud/filestore/libs/storage/tablet/tablet_state_impl.h index 35df452a079..04ed56544a6 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state_impl.h +++ b/cloud/filestore/libs/storage/tablet/tablet_state_impl.h @@ -43,6 +43,8 @@ struct TIndexTabletState::TImpl TSessionLockMultiMap LocksByHandle; ui64 MaxSessionHistoryEntryId = 1; + TNodeToSessionStat NodeToSessionStat; + TWriteRequestList WriteBatch; TRangeLocks RangeLocks; diff --git a/cloud/filestore/libs/storage/tablet/tablet_state_sessions.cpp b/cloud/filestore/libs/storage/tablet/tablet_state_sessions.cpp index 99270f8af88..742f62b8911 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_state_sessions.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_state_sessions.cpp @@ -509,6 +509,25 @@ TSessionHandle* TIndexTabletState::CreateHandle( Impl->HandleById.emplace(handle->GetHandle(), handle.get()); Impl->NodeRefsByHandle[proto.GetNodeId()]++; + { + const auto nodeId = handle->GetNodeId(); + const auto flags = handle->GetFlags(); + ChangeNodeCounters(Impl->NodeToSessionStat.GetKind(nodeId), -1); + if (HasFlag(flags, NProto::TCreateHandleRequest::E_WRITE)) { + ChangeNodeCounters( + Impl->NodeToSessionStat.AddWrite( + nodeId, + session->GetSessionId()), + 1); + } else if (HasFlag(flags, NProto::TCreateHandleRequest::E_READ)) { + ChangeNodeCounters( + Impl->NodeToSessionStat.AddRead( + nodeId, + session->GetSessionId()), + 1); + } + } + return handle.release(); } @@ -526,6 +545,27 @@ void TIndexTabletState::RemoveHandle(TSessionHandle* handle) if (--(it->second) == 0) { Impl->NodeRefsByHandle.erase(it); } + + { + const auto nodeId = handle->GetNodeId(); + ChangeNodeCounters(Impl->NodeToSessionStat.GetKind(nodeId), -1); + if (HasFlag(handle->GetFlags(), NProto::TCreateHandleRequest::E_WRITE)) + { + ChangeNodeCounters( + Impl->NodeToSessionStat.RemoveWrite( + nodeId, + handle->GetSessionId()), + 1); + } else if ( + HasFlag(handle->GetFlags(), NProto::TCreateHandleRequest::E_READ)) + { + ChangeNodeCounters( + Impl->NodeToSessionStat.RemoveRead( + nodeId, + handle->GetSessionId()), + 1); + } + } } TSessionHandle* TIndexTabletState::FindHandle(ui64 handle) const @@ -538,6 +578,30 @@ TSessionHandle* TIndexTabletState::FindHandle(ui64 handle) const return nullptr; } +void TIndexTabletState::ChangeNodeCounters( + const TNodeToSessionStat::EKind nodeKind, + i64 amount) +{ + switch (nodeKind) { + case TNodeToSessionStat::EKind::None: + break; + case TNodeToSessionStat::EKind::NodesOpenForWritingBySingleSession: + NodeToSessionCounters.NodesOpenForWritingBySingleSession += amount; + break; + case TNodeToSessionStat::EKind::NodesOpenForWritingByMultipleSessions: + NodeToSessionCounters.NodesOpenForWritingByMultipleSessions += + amount; + break; + case TNodeToSessionStat::EKind::NodesOpenForReadingBySingleSession: + NodeToSessionCounters.NodesOpenForReadingBySingleSession += amount; + break; + case TNodeToSessionStat::EKind::NodesOpenForReadingByMultipleSessions: + NodeToSessionCounters.NodesOpenForReadingByMultipleSessions += + amount; + break; + } +} + TSessionHandle* TIndexTabletState::CreateHandle( TIndexTabletDatabase& db, TSession* session, diff --git a/cloud/filestore/libs/storage/tablet/tablet_ut_nodes.cpp b/cloud/filestore/libs/storage/tablet/tablet_ut_nodes.cpp index 2951e53bb6c..f7f9bdd37b6 100644 --- a/cloud/filestore/libs/storage/tablet/tablet_ut_nodes.cpp +++ b/cloud/filestore/libs/storage/tablet/tablet_ut_nodes.cpp @@ -1201,6 +1201,141 @@ Y_UNIT_TEST_SUITE(TIndexTabletTest_Nodes) } } + Y_UNIT_TEST(ShouldStatOpenedFiles) + { + NProto::TStorageConfig storageConfig; + storageConfig.SetNodeIndexCacheMaxNodes(32); + TTestEnv env({}, storageConfig); + env.CreateSubDomain("nfs"); + auto registry = env.GetRegistry(); + + ui32 nodeIdx = env.CreateNode("nfs"); + ui64 tabletId = env.BootIndexTablet(nodeIdx); + + TIndexTabletClient tablet(env.GetRuntime(), nodeIdx, tabletId); + tablet.InitSession("client", "session"); + +#define COUNTERS_VALIDATE_WS_WM_RS_RM(wo, wm, ro, rm) \ + { \ + tablet.SendRequest(tablet.CreateUpdateCounters()); \ + env.GetRuntime().DispatchEvents({}, TDuration::Seconds(1)); \ + TTestRegistryVisitor visitor; \ + registry->Visit(TInstant::Zero(), visitor); \ + visitor.ValidateExpectedCounters({ \ + {{{"filesystem", "test"}, \ + {"sensor", "NodesOpenForWritingBySingleSession"}}, \ + wo}, \ + {{{"filesystem", "test"}, \ + {"sensor", "NodesOpenForWritingByMultipleSessions"}}, \ + wm}, \ + {{{"filesystem", "test"}, \ + {"sensor", "NodesOpenForReadingBySingleSession"}}, \ + ro}, \ + {{{"filesystem", "test"}, \ + {"sensor", "NodesOpenForReadingByMultipleSessions"}}, \ + rm}, \ + }); \ + } + + auto id = CreateNode(tablet, TCreateNodeArgs::File(RootNodeId, "test")); + { + auto handleS1W = CreateHandle(tablet, id); + + tablet.WriteData(handleS1W, 0, 1, '1'); + tablet.WriteData(handleS1W, 1, 1024, '2'); + + { + auto handleS1R = + CreateHandle(tablet, id, {}, TCreateHandleArgs::RDNLY); + tablet.ReadData(handleS1R, 10, 10); + COUNTERS_VALIDATE_WS_WM_RS_RM(1, 0, 0, 0); + tablet.DestroyHandle(handleS1R); + } + + COUNTERS_VALIDATE_WS_WM_RS_RM(1, 0, 0, 0); + tablet.DestroyHandle(handleS1W); + + { + auto handleS1R = + CreateHandle(tablet, id, {}, TCreateHandleArgs::RDNLY); + tablet.ReadData(handleS1R, 10, 10); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 1, 0); + + auto handleS1W = CreateHandle(tablet, id); + COUNTERS_VALIDATE_WS_WM_RS_RM(1, 0, 0, 0); + + { + TIndexTabletClient tablet2( + env.GetRuntime(), + nodeIdx, + tabletId); + tablet2.InitSession("client2", "session2"); + auto handleS2R = + CreateHandle(tablet2, id, {}, TCreateHandleArgs::RDNLY); + COUNTERS_VALIDATE_WS_WM_RS_RM(1, 0, 0, 0); + + tablet2.DestroyHandle(handleS2R); + auto handleS2W = CreateHandle(tablet2, id, {}); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 1, 0, 0); + tablet2.DestroyHandle(handleS2W); + } + + tablet.DestroyHandle(handleS1W); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 1, 0); + + { + auto node2 = CreateNode( + tablet, + TCreateNodeArgs::File(RootNodeId, "test2")); + auto handleS1W2 = CreateHandle(tablet, node2); + tablet.WriteData(handleS1W2, 0, 1, '1'); + COUNTERS_VALIDATE_WS_WM_RS_RM(1, 0, 1, 0); + tablet.DestroyHandle(handleS1W2); + + { + auto handleS1R = CreateHandle( + tablet, + node2, + {}, + TCreateHandleArgs::RDNLY); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 2, 0); + tablet.DestroyHandle(handleS1R); + } + } + + { + TIndexTabletClient tablet2( + env.GetRuntime(), + nodeIdx, + tabletId); + tablet2.InitSession("client2", "session2"); + auto handleS2R = + CreateHandle(tablet2, id, {}, TCreateHandleArgs::RDNLY); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 0, 1); + tablet2.DestroyHandle(handleS2R); + } + + tablet.DestroyHandle(handleS1R); + } + } + + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 0, 0); + + { + auto handleS1R = + CreateHandle(tablet, id, {}, TCreateHandleArgs::RDNLY); + tablet.ReadData(handleS1R, 10, 10); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 1, 0); + tablet.RebootTablet(); + tablet.RecoverSession(); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 1, 0); + tablet.DestroyHandle(handleS1R); + COUNTERS_VALIDATE_WS_WM_RS_RM(0, 0, 0, 0); + } + +#undef COUNTERS_VALIDATE_WS_WM_RS_RM + } + Y_UNIT_TEST(ShouldInvalidateNodeIndexCacheUponIndexOps) { NProto::TStorageConfig storageConfig;