From 18848f203e4a440d7dc4807685ba31561ce3230f Mon Sep 17 00:00:00 2001 From: Ilia Shakhov Date: Thu, 29 Feb 2024 15:21:22 +0300 Subject: [PATCH] Dont return shared nodes for serverless KIKIMR-21128 (#2264) (#2305) --- ydb/core/viewer/json_nodes.h | 30 +++-- ydb/core/viewer/viewer_ut.cpp | 213 +++++++++++++++++++++++----------- 2 files changed, 158 insertions(+), 85 deletions(-) diff --git a/ydb/core/viewer/json_nodes.h b/ydb/core/viewer/json_nodes.h index f663e38a3ad4..ceab8a8cf8cf 100644 --- a/ydb/core/viewer/json_nodes.h +++ b/ydb/core/viewer/json_nodes.h @@ -411,27 +411,25 @@ class TJsonNodes : public TViewerPipeClient { const auto localPathId = entry.DomainInfo->DomainKey.LocalPathId; FilterSubDomainKey = TSubDomainKey(ownerId, localPathId); } + + if (FilterTenant.empty()) { + RequestForTenant(path); + } + if (entry.DomainInfo->ResourcesDomainKey && entry.DomainInfo->DomainKey != entry.DomainInfo->ResourcesDomainKey) { TPathId resourceDomainKey(entry.DomainInfo->ResourcesDomainKey); BLOG_TRACE("Requesting navigate for resource domain " << resourceDomainKey); RequestSchemeCacheNavigate(resourceDomainKey); ++RequestsBeforeNodeList; - } else { - if (FilterTenant.empty()) { - RequestForTenant(path); - } - if (Storage) { - if (entry.DomainDescription) { - for (const auto& storagePool : entry.DomainDescription->Description.GetStoragePools()) { - TString storagePoolName = storagePool.GetName(); - THolder request = MakeHolder(); - request->Record.SetReturnAllMatchingGroups(true); - request->Record.AddGroupParameters()->MutableStoragePoolSpecifier()->SetName(storagePoolName); - BLOG_TRACE("Requesting BSControllerSelectGroups for " << storagePoolName); - RequestBSControllerSelectGroups(std::move(request)); - ++RequestsBeforeNodeList; - } - } + } else if (Storage && entry.DomainDescription) { + for (const auto& storagePool : entry.DomainDescription->Description.GetStoragePools()) { + TString storagePoolName = storagePool.GetName(); + THolder request = MakeHolder(); + request->Record.SetReturnAllMatchingGroups(true); + request->Record.AddGroupParameters()->MutableStoragePoolSpecifier()->SetName(storagePoolName); + BLOG_TRACE("Requesting BSControllerSelectGroups for " << storagePoolName); + RequestBSControllerSelectGroups(std::move(request)); + ++RequestsBeforeNodeList; } } } else { diff --git a/ydb/core/viewer/viewer_ut.cpp b/ydb/core/viewer/viewer_ut.cpp index 6fbcfba9583a..d3f85f24837d 100644 --- a/ydb/core/viewer/viewer_ut.cpp +++ b/ydb/core/viewer/viewer_ut.cpp @@ -601,6 +601,89 @@ Y_UNIT_TEST_SUITE(Viewer) { StorageSpaceTest("space", NKikimrWhiteboard::EFlag::Green, 90, 100, true); } + const TPathId SHARED_DOMAIN_KEY = {7000000000, 1}; + const TPathId SERVERLESS_DOMAIN_KEY = {7000000000, 2}; + const TPathId SERVERLESS_TABLE = {7000000001, 2}; + + void ChangeNavigateKeySetResultServerless(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr* ev, + TTestActorRuntime& runtime) { + TSchemeCacheNavigate::TEntry& entry((*ev)->Get()->Request->ResultSet.front()); + TString path = CanonizePath(entry.Path); + if (path == "/Root/serverless" || entry.TableId.PathId == SERVERLESS_DOMAIN_KEY) { + entry.Status = TSchemeCacheNavigate::EStatus::Ok; + entry.Kind = TSchemeCacheNavigate::EKind::KindExtSubdomain; + entry.DomainInfo = MakeIntrusive(SERVERLESS_DOMAIN_KEY, SHARED_DOMAIN_KEY); + } else if (path == "/Root/shared" || entry.TableId.PathId == SHARED_DOMAIN_KEY) { + entry.Status = TSchemeCacheNavigate::EStatus::Ok; + entry.Kind = TSchemeCacheNavigate::EKind::KindExtSubdomain; + entry.DomainInfo = MakeIntrusive(SHARED_DOMAIN_KEY, SHARED_DOMAIN_KEY); + auto domains = runtime.GetAppData().DomainsInfo; + auto domain = domains->Domains.begin()->second; + ui64 hiveId = domains->GetHive(domain->DefaultHiveUid); + entry.DomainInfo->Params.SetHive(hiveId); + } else if (path == "/Root/serverless/users" || entry.TableId.PathId == SERVERLESS_TABLE) { + entry.Status = TSchemeCacheNavigate::EStatus::Ok; + entry.Kind = TSchemeCacheNavigate::EKind::KindTable; + entry.DomainInfo = MakeIntrusive(SERVERLESS_DOMAIN_KEY, SHARED_DOMAIN_KEY); + auto dirEntryInfo = MakeIntrusive(); + dirEntryInfo->Info.SetSchemeshardId(SERVERLESS_TABLE.OwnerId); + dirEntryInfo->Info.SetPathId(SERVERLESS_TABLE.LocalPathId); + entry.Self = dirEntryInfo; + } + } + + void ChangeBoardInfoServerless(TEvStateStorage::TEvBoardInfo::TPtr* ev, + const std::vector& sharedDynNodes = {}, + const std::vector& exclusiveDynNodes = {}) { + auto *record = (*ev)->Get(); + using EStatus = TEvStateStorage::TEvBoardInfo::EStatus; + if (record->Path == "gpc+/Root/serverless" && !exclusiveDynNodes.empty()) { + const_cast(record->Status) = EStatus::Ok; + for (auto exclusiveDynNodeId : exclusiveDynNodes) { + TActorId actorOnExclusiveDynNode = TActorId(exclusiveDynNodeId, 0, 0, 0); + record->InfoEntries[actorOnExclusiveDynNode] = {}; + } + } else if (record->Path == "gpc+/Root/shared" && !sharedDynNodes.empty()) { + const_cast(record->Status) = EStatus::Ok; + for (auto sharedDynNodeId : sharedDynNodes) { + TActorId actorOnSharedDynNode = TActorId(sharedDynNodeId, 0, 0, 0); + record->InfoEntries[actorOnSharedDynNode] = {}; + } + } + } + + void ChangeResponseHiveNodeStatsServerless(TEvHive::TEvResponseHiveNodeStats::TPtr* ev, + size_t sharedDynNode = 0, + size_t exclusiveDynNode = 0, + size_t exclusiveDynNodeWithTablet = 0) { + auto &record = (*ev)->Get()->Record; + if (sharedDynNode) { + auto *sharedNodeStats = record.MutableNodeStats()->Add(); + sharedNodeStats->SetNodeId(sharedDynNode); + sharedNodeStats->MutableNodeDomain()->SetSchemeShard(SHARED_DOMAIN_KEY.OwnerId); + sharedNodeStats->MutableNodeDomain()->SetPathId(SHARED_DOMAIN_KEY.LocalPathId); + } + + if (exclusiveDynNode) { + auto *exclusiveNodeStats = record.MutableNodeStats()->Add(); + exclusiveNodeStats->SetNodeId(exclusiveDynNode); + exclusiveNodeStats->MutableNodeDomain()->SetSchemeShard(SERVERLESS_DOMAIN_KEY.OwnerId); + exclusiveNodeStats->MutableNodeDomain()->SetPathId(SERVERLESS_DOMAIN_KEY.LocalPathId); + } + + if (exclusiveDynNodeWithTablet) { + auto *exclusiveDynNodeWithTabletStats = record.MutableNodeStats()->Add(); + exclusiveDynNodeWithTabletStats->SetNodeId(exclusiveDynNodeWithTablet); + exclusiveDynNodeWithTabletStats->MutableNodeDomain()->SetSchemeShard(SERVERLESS_DOMAIN_KEY.OwnerId); + exclusiveDynNodeWithTabletStats->MutableNodeDomain()->SetPathId(SERVERLESS_DOMAIN_KEY.LocalPathId); + + auto *stateStats = exclusiveDynNodeWithTabletStats->MutableStateStats()->Add(); + stateStats->SetTabletType(NKikimrTabletBase::TTabletTypes::DataShard); + stateStats->SetVolatileState(NKikimrHive::TABLET_VOLATILE_STATE_RUNNING); + stateStats->SetCount(1); + } + } + Y_UNIT_TEST(ServerlessNodesPage) { TPortManager tp; @@ -622,7 +705,7 @@ Y_UNIT_TEST_SUITE(Viewer) { TAutoPtr handle; THttpRequest httpReq(HTTP_METHOD_GET); - httpReq.CgiParameters.emplace("tenant", "/Root/serverless"); + httpReq.CgiParameters.emplace("path", "/Root/serverless"); httpReq.CgiParameters.emplace("tablets", "true"); httpReq.CgiParameters.emplace("enums", "true"); httpReq.CgiParameters.emplace("sort", ""); @@ -631,6 +714,39 @@ Y_UNIT_TEST_SUITE(Viewer) { TMonService2HttpRequest monReq(nullptr, &httpReq, nullptr, page.Get(), "/json/nodes", nullptr); auto request = MakeHolder(monReq); + size_t staticNodeId = 0; + size_t sharedDynNodeId = 0; + auto observerFunc = [&](TAutoPtr& ev) { + switch (ev->GetTypeRewrite()) { + case TEvTxProxySchemeCache::EvNavigateKeySetResult: { + auto *x = reinterpret_cast(&ev); + ChangeNavigateKeySetResultServerless(x, runtime); + break; + } + case TEvInterconnect::EvNodesInfo: { + auto *x = reinterpret_cast(&ev); + TVector &nodes = (*x)->Get()->Nodes; + UNIT_ASSERT_EQUAL(nodes.size(), 2); + staticNodeId = nodes[0]; + sharedDynNodeId = nodes[1]; + break; + } + case TEvStateStorage::EvBoardInfo: { + auto *x = reinterpret_cast(&ev); + ChangeBoardInfoServerless(x, { sharedDynNodeId }); + break; + } + case TEvHive::EvResponseHiveNodeStats: { + auto *x = reinterpret_cast(&ev); + ChangeResponseHiveNodeStatsServerless(x, sharedDynNodeId); + break; + } + } + + return TTestActorRuntime::EEventAction::PROCESS; + }; + runtime.SetObserverFunc(observerFunc); + runtime.Send(new IEventHandle(NKikimr::NViewer::MakeViewerID(0), sender, request.Release(), 0)); NMon::TEvHttpInfoRes* result = runtime.GrabEdgeEvent(handle); @@ -669,7 +785,7 @@ Y_UNIT_TEST_SUITE(Viewer) { TAutoPtr handle; THttpRequest httpReq(HTTP_METHOD_GET); - httpReq.CgiParameters.emplace("tenant", "/Root/serverless"); + httpReq.CgiParameters.emplace("path", "/Root/serverless"); httpReq.CgiParameters.emplace("tablets", "true"); httpReq.CgiParameters.emplace("enums", "true"); httpReq.CgiParameters.emplace("sort", ""); @@ -683,6 +799,11 @@ Y_UNIT_TEST_SUITE(Viewer) { size_t exclusiveDynNodeId = 0; auto observerFunc = [&](TAutoPtr& ev) { switch (ev->GetTypeRewrite()) { + case TEvTxProxySchemeCache::EvNavigateKeySetResult: { + auto *x = reinterpret_cast(&ev); + ChangeNavigateKeySetResultServerless(x, runtime); + break; + } case TEvInterconnect::EvNodesInfo: { auto *x = reinterpret_cast(&ev); TVector &nodes = (*x)->Get()->Nodes; @@ -694,11 +815,12 @@ Y_UNIT_TEST_SUITE(Viewer) { } case TEvStateStorage::EvBoardInfo: { auto *x = reinterpret_cast(&ev); - auto *record = (*x)->Get(); - using EStatus = TEvStateStorage::TEvBoardInfo::EStatus; - const_cast(record->Status) = EStatus::Ok; - TActorId actorOnExclusiveDynNode = TActorId(exclusiveDynNodeId, 0, 0, 0); - record->InfoEntries[actorOnExclusiveDynNode] = {}; + ChangeBoardInfoServerless(x, { sharedDynNodeId }, { exclusiveDynNodeId }); + break; + } + case TEvHive::EvResponseHiveNodeStats: { + auto *x = reinterpret_cast(&ev); + ChangeResponseHiveNodeStatsServerless(x, sharedDynNodeId, exclusiveDynNodeId); break; } } @@ -748,7 +870,7 @@ Y_UNIT_TEST_SUITE(Viewer) { TAutoPtr handle; THttpRequest httpReq(HTTP_METHOD_GET); - httpReq.CgiParameters.emplace("tenant", "Root/shared"); + httpReq.CgiParameters.emplace("path", "/Root/shared"); httpReq.CgiParameters.emplace("tablets", "true"); httpReq.CgiParameters.emplace("enums", "true"); httpReq.CgiParameters.emplace("sort", ""); @@ -762,6 +884,11 @@ Y_UNIT_TEST_SUITE(Viewer) { size_t exclusiveDynNodeId = 0; auto observerFunc = [&](TAutoPtr& ev) { switch (ev->GetTypeRewrite()) { + case TEvTxProxySchemeCache::EvNavigateKeySetResult: { + auto *x = reinterpret_cast(&ev); + ChangeNavigateKeySetResultServerless(x, runtime); + break; + } case TEvInterconnect::EvNodesInfo: { auto *x = reinterpret_cast(&ev); TVector &nodes = (*x)->Get()->Nodes; @@ -773,11 +900,12 @@ Y_UNIT_TEST_SUITE(Viewer) { } case TEvStateStorage::EvBoardInfo: { auto *x = reinterpret_cast(&ev); - auto *record = (*x)->Get(); - using EStatus = TEvStateStorage::TEvBoardInfo::EStatus; - const_cast(record->Status) = EStatus::Ok; - TActorId actorOnSharedDynNode = TActorId(sharedDynNodeId, 0, 0, 0); - record->InfoEntries[actorOnSharedDynNode] = {}; + ChangeBoardInfoServerless(x, { sharedDynNodeId }, { exclusiveDynNodeId }); + break; + } + case TEvHive::EvResponseHiveNodeStats: { + auto *x = reinterpret_cast(&ev); + ChangeResponseHiveNodeStatsServerless(x, sharedDynNodeId, exclusiveDynNodeId); break; } } @@ -827,7 +955,6 @@ Y_UNIT_TEST_SUITE(Viewer) { TAutoPtr handle; THttpRequest httpReq(HTTP_METHOD_GET); - httpReq.CgiParameters.emplace("tenant", "/Root/serverless"); httpReq.CgiParameters.emplace("path", "/Root/serverless/users"); httpReq.CgiParameters.emplace("tablets", "true"); httpReq.CgiParameters.emplace("enums", "true"); @@ -837,10 +964,6 @@ Y_UNIT_TEST_SUITE(Viewer) { TMonService2HttpRequest monReq(nullptr, &httpReq, nullptr, page.Get(), "/json/nodes", nullptr); auto request = MakeHolder(monReq); - const TPathId SERVERLESS_DOMAIN_KEY = {7000000000, 2}; - const TPathId SHARED_DOMAIN_KEY = {7000000000, 1}; - const TPathId SERVERLESS_TABLE = {7000000001, 2}; - size_t staticNodeId = 0; size_t sharedDynNodeId = 0; size_t exclusiveDynNodeId = 0; @@ -849,29 +972,7 @@ Y_UNIT_TEST_SUITE(Viewer) { switch (ev->GetTypeRewrite()) { case TEvTxProxySchemeCache::EvNavigateKeySetResult: { auto *x = reinterpret_cast(&ev); - TSchemeCacheNavigate::TEntry& entry((*x)->Get()->Request->ResultSet.front()); - TString path = CanonizePath(entry.Path); - if (path == "/Root/serverless" || entry.TableId.PathId == SERVERLESS_DOMAIN_KEY) { - entry.Status = TSchemeCacheNavigate::EStatus::Ok; - entry.Kind = TSchemeCacheNavigate::EKind::KindExtSubdomain; - entry.DomainInfo = MakeIntrusive(SERVERLESS_DOMAIN_KEY, SHARED_DOMAIN_KEY); - } else if (path == "/Root/shared" || entry.TableId.PathId == SHARED_DOMAIN_KEY) { - entry.Status = TSchemeCacheNavigate::EStatus::Ok; - entry.Kind = TSchemeCacheNavigate::EKind::KindExtSubdomain; - entry.DomainInfo = MakeIntrusive(SHARED_DOMAIN_KEY, SHARED_DOMAIN_KEY); - auto domains = runtime.GetAppData().DomainsInfo; - auto domain = domains->Domains.begin()->second; - ui64 hiveId = domains->GetHive(domain->DefaultHiveUid); - entry.DomainInfo->Params.SetHive(hiveId); - } else if (path == "/Root/serverless/users" || entry.TableId.PathId == SERVERLESS_TABLE) { - entry.Status = TSchemeCacheNavigate::EStatus::Ok; - entry.Kind = TSchemeCacheNavigate::EKind::KindTable; - entry.DomainInfo = MakeIntrusive(SERVERLESS_DOMAIN_KEY, SHARED_DOMAIN_KEY); - auto dirEntryInfo = MakeIntrusive(); - dirEntryInfo->Info.SetSchemeshardId(SERVERLESS_TABLE.OwnerId); - dirEntryInfo->Info.SetPathId(SERVERLESS_TABLE.LocalPathId); - entry.Self = dirEntryInfo; - } + ChangeNavigateKeySetResultServerless(x, runtime); break; } case TEvInterconnect::EvNodesInfo: { @@ -886,38 +987,12 @@ Y_UNIT_TEST_SUITE(Viewer) { } case TEvStateStorage::EvBoardInfo: { auto *x = reinterpret_cast(&ev); - auto *record = (*x)->Get(); - using EStatus = TEvStateStorage::TEvBoardInfo::EStatus; - const_cast(record->Status) = EStatus::Ok; - TActorId actorOnExclusiveDynNode = TActorId(exclusiveDynNodeId, 0, 0, 0); - record->InfoEntries[actorOnExclusiveDynNode] = {}; - TActorId actorOnSecondExclusiveDynNode = TActorId(secondExclusiveDynNodeId, 0, 0, 0); - record->InfoEntries[actorOnSecondExclusiveDynNode] = {}; + ChangeBoardInfoServerless(x, { sharedDynNodeId }, { exclusiveDynNodeId, secondExclusiveDynNodeId }); break; } case TEvHive::EvResponseHiveNodeStats: { auto *x = reinterpret_cast(&ev); - auto &record = (*x)->Get()->Record; - auto *sharedNodeStats = record.MutableNodeStats()->Add(); - sharedNodeStats->SetNodeId(sharedDynNodeId); - sharedNodeStats->MutableNodeDomain()->SetSchemeShard(SHARED_DOMAIN_KEY.OwnerId); - sharedNodeStats->MutableNodeDomain()->SetPathId(SHARED_DOMAIN_KEY.LocalPathId); - - auto *exclusiveNodeStats = record.MutableNodeStats()->Add(); - exclusiveNodeStats->SetNodeId(exclusiveDynNodeId); - exclusiveNodeStats->MutableNodeDomain()->SetSchemeShard(SERVERLESS_DOMAIN_KEY.OwnerId); - exclusiveNodeStats->MutableNodeDomain()->SetPathId(SERVERLESS_DOMAIN_KEY.LocalPathId); - - auto *secondExclusiveNodeStats = record.MutableNodeStats()->Add(); - secondExclusiveNodeStats->SetNodeId(secondExclusiveDynNodeId); - secondExclusiveNodeStats->MutableNodeDomain()->SetSchemeShard(SERVERLESS_DOMAIN_KEY.OwnerId); - secondExclusiveNodeStats->MutableNodeDomain()->SetPathId(SERVERLESS_DOMAIN_KEY.LocalPathId); - - // filtered one datashard from /Root/serverless/users - auto *stateStats = secondExclusiveNodeStats->MutableStateStats()->Add(); - stateStats->SetTabletType(NKikimrTabletBase::TTabletTypes::DataShard); - stateStats->SetVolatileState(NKikimrHive::TABLET_VOLATILE_STATE_RUNNING); - stateStats->SetCount(1); + ChangeResponseHiveNodeStatsServerless(x, sharedDynNodeId, exclusiveDynNodeId, secondExclusiveDynNodeId); break; } }