diff --git a/ydb/core/viewer/json_handlers_viewer.cpp b/ydb/core/viewer/json_handlers_viewer.cpp index 688ffc79cf32..a9ec2d7c2cb9 100644 --- a/ydb/core/viewer/json_handlers_viewer.cpp +++ b/ydb/core/viewer/json_handlers_viewer.cpp @@ -218,7 +218,7 @@ void InitViewerHiveStatsJsonHandler(TJsonHandlers& handlers) { } void InitViewerTenantInfoJsonHandler(TJsonHandlers &handlers) { - handlers.AddHandler("/viewer/tenantinfo", new TJsonHandler(TJsonTenantInfo::GetSwagger())); + handlers.AddHandler("/viewer/tenantinfo", new TJsonHandler(TJsonTenantInfo::GetSwagger()), 2); } void InitViewerWhoAmIJsonHandler(TJsonHandlers& handlers) { diff --git a/ydb/core/viewer/protos/viewer.proto b/ydb/core/viewer/protos/viewer.proto index cca076c1426e..d017d13e594e 100644 --- a/ydb/core/viewer/protos/viewer.proto +++ b/ydb/core/viewer/protos/viewer.proto @@ -381,7 +381,8 @@ message TTenant { uint64 StorageGroups = 40; uint64 StorageAllocatedLimit = 41; Ydb.Cms.DatabaseQuotas DatabaseQuotas = 42; - repeated TStorageUsage StorageUsage = 43; + repeated TStorageUsage TablesStorage = 44; + repeated TStorageUsage DatabaseStorage = 45; } message TTenants { @@ -391,6 +392,7 @@ message TTenants { message TTenantInfo { repeated TTenant TenantInfo = 1; repeated string Errors = 2; + uint32 Version = 3; } message TStoragePDisk { diff --git a/ydb/core/viewer/viewer_tenantinfo.h b/ydb/core/viewer/viewer_tenantinfo.h index 30789adce2d3..e2e83cd9ba75 100644 --- a/ydb/core/viewer/viewer_tenantinfo.h +++ b/ydb/core/viewer/viewer_tenantinfo.h @@ -46,9 +46,11 @@ class TJsonTenantInfo : public TViewerPipeClient { THashMap> TenantNodes; THashMap OffloadMergedTabletStateResponse; THashMap OffloadMergedSystemStateResponse; + THashMap StoragePoolType; TTabletId RootHiveId = 0; TString RootId; // id of root domain (tenant) NKikimrViewer::TTenantInfo Result; + std::optional> GetStoragePoolsResponse; struct TStorageQuota { uint64 SoftQuota = 0; @@ -124,6 +126,7 @@ class TJsonTenantInfo : public TViewerPipeClient { if (Storage) { RequestHiveStorageStats(RootHiveId); } + GetStoragePoolsResponse = RequestBSControllerPools(); if (Requests == 0) { ReplyAndPassAway(); @@ -154,9 +157,10 @@ class TJsonTenantInfo : public TViewerPipeClient { hFunc(TEvViewer::TEvViewerResponse, Handle); hFunc(TEvents::TEvUndelivered, Undelivered); hFunc(TEvInterconnect::TEvNodeDisconnected, Disconnected); - hFunc(TEvTabletPipe::TEvClientConnected, TBase::Handle); + hFunc(TEvTabletPipe::TEvClientConnected, Handle); hFunc(TEvStateStorage::TEvBoardInfo, Handle); hFunc(NHealthCheck::TEvSelfCheckResultProto, Handle); + hFunc(NSysView::TEvSysView::TEvGetStoragePoolsResponse, Handle); cFunc(TEvents::TSystem::Wakeup, HandleTimeout); } } @@ -534,8 +538,33 @@ class TJsonTenantInfo : public TViewerPipeClient { return type; } + void Handle(TEvTabletPipe::TEvClientConnected::TPtr& ev) { + if (ev->Get()->Status != NKikimrProto::OK) { + TString error = TStringBuilder() << "Failed to establish pipe: " << NKikimrProto::EReplyStatus_Name(ev->Get()->Status); + if (ev->Get()->TabletId == GetBSControllerId()) { + if (GetStoragePoolsResponse.has_value()) { + GetStoragePoolsResponse->Error(error); + } + } + } + TBase::Handle(ev); // all RequestDone() are handled by base handler + } + + void Handle(NSysView::TEvSysView::TEvGetStoragePoolsResponse::TPtr& ev) { + GetStoragePoolsResponse->Set(std::move(ev)); + + if (GetStoragePoolsResponse && GetStoragePoolsResponse->IsOk()) { + for (const NKikimrSysView::TStoragePoolEntry& entry : GetStoragePoolsResponse->Get()->Record.GetEntries()) { + StoragePoolType[entry.GetInfo().GetName()] = GetStorageType(entry.GetInfo().GetKind()); + } + } + + RequestDone(); + } + void ReplyAndPassAway() override { BLOG_TRACE("ReplyAndPassAway() started"); + Result.SetVersion(2); TIntrusivePtr domains = AppData()->DomainsInfo; auto *domain = domains->GetDomain(); THashMap OverallByDomainId; @@ -666,6 +695,7 @@ class TJsonTenantInfo : public TViewerPipeClient { } if (Storage) { + THashMap databaseStorageByType; auto itHiveStorageStats = HiveStorageStats.find(hiveId); if (itHiveStorageStats != HiveStorageStats.end()) { const NKikimrHive::TEvResponseHiveStorageStats& record = itHiveStorageStats->second.Get()->Record; @@ -675,9 +705,12 @@ class TJsonTenantInfo : public TViewerPipeClient { uint64 storageGroups = 0; for (const NKikimrHive::THiveStoragePoolStats& poolStat : record.GetPools()) { if (poolStat.GetName().StartsWith(tenantBySubDomainKey.GetName())) { + NKikimrViewer::TStorageUsage::EType storageType = StoragePoolType[poolStat.GetName()]; for (const NKikimrHive::THiveStorageGroupStats& groupStat : poolStat.GetGroups()) { storageAllocatedSize += groupStat.GetAllocatedSize(); storageAvailableSize += groupStat.GetAvailableSize(); + databaseStorageByType[storageType] += groupStat.GetAllocatedSize(); + databaseStorageByType[storageType] += groupStat.GetAvailableSize(); storageMinAvailableSize = std::min(storageMinAvailableSize, groupStat.GetAvailableSize()); ++storageGroups; } @@ -690,7 +723,7 @@ class TJsonTenantInfo : public TViewerPipeClient { tenant.SetStorageGroups(storageGroups); } - THashMap storageUsageByType; + THashMap tablesStorageByType; THashMap storageQuotasByType; for (const auto& quota : tenant.GetDatabaseQuotas().storage_quotas()) { @@ -703,11 +736,11 @@ class TJsonTenantInfo : public TViewerPipeClient { if (entry.DomainDescription) { for (const auto& poolUsage : entry.DomainDescription->Description.GetDiskSpaceUsage().GetStoragePoolsUsage()) { auto type = GetStorageType(poolUsage.GetPoolKind()); - storageUsageByType[type] += poolUsage.GetTotalSize(); + tablesStorageByType[type] += poolUsage.GetTotalSize(); } - if (storageUsageByType.empty() && entry.DomainDescription->Description.HasDiskSpaceUsage()) { - storageUsageByType[GuessStorageType(entry.DomainDescription->Description)] = + if (tablesStorageByType.empty() && entry.DomainDescription->Description.HasDiskSpaceUsage()) { + tablesStorageByType[GuessStorageType(entry.DomainDescription->Description)] = entry.DomainDescription->Description.GetDiskSpaceUsage().GetTables().GetTotalSize(); } @@ -718,17 +751,23 @@ class TJsonTenantInfo : public TViewerPipeClient { } } - for (const auto& [type, size] : storageUsageByType) { - auto& storageUsage = *tenant.AddStorageUsage(); - storageUsage.SetType(type); - storageUsage.SetSize(size); + for (const auto& [type, size] : tablesStorageByType) { auto it = storageQuotasByType.find(type); + auto& tablesStorage = *tenant.AddTablesStorage(); + tablesStorage.SetType(type); + tablesStorage.SetSize(size); if (it != storageQuotasByType.end()) { - storageUsage.SetLimit(it->second.HardQuota); - storageUsage.SetSoftQuota(it->second.SoftQuota); - storageUsage.SetHardQuota(it->second.HardQuota); + tablesStorage.SetLimit(it->second.SoftQuota); + tablesStorage.SetSoftQuota(it->second.SoftQuota); + tablesStorage.SetHardQuota(it->second.HardQuota); } } + + for (const auto& [type, size] : databaseStorageByType) { + auto& databaseStorage = *tenant.AddDatabaseStorage(); + databaseStorage.SetType(type); + databaseStorage.SetSize(size); + } } THashSet tenantNodes;