diff --git a/ydb/core/viewer/protos/viewer.proto b/ydb/core/viewer/protos/viewer.proto index cca076c1426e..af25c48c5897 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 TabletStorage = 44; + repeated TStorageUsage DatabaseStorage = 45; } message TTenants { diff --git a/ydb/core/viewer/viewer_tenantinfo.h b/ydb/core/viewer/viewer_tenantinfo.h index 30789adce2d3..e0335dbc0e63 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,6 +538,30 @@ 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"); TIntrusivePtr domains = AppData()->DomainsInfo; @@ -666,6 +694,7 @@ class TJsonTenantInfo : public TViewerPipeClient { } if (Storage) { + THashMap blobStorageByType; auto itHiveStorageStats = HiveStorageStats.find(hiveId); if (itHiveStorageStats != HiveStorageStats.end()) { const NKikimrHive::TEvResponseHiveStorageStats& record = itHiveStorageStats->second.Get()->Record; @@ -675,9 +704,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(); + blobStorageByType[storageType] += groupStat.GetAllocatedSize(); + blobStorageByType[storageType] += groupStat.GetAvailableSize(); storageMinAvailableSize = std::min(storageMinAvailableSize, groupStat.GetAvailableSize()); ++storageGroups; } @@ -719,16 +751,22 @@ class TJsonTenantInfo : public TViewerPipeClient { } for (const auto& [type, size] : storageUsageByType) { - auto& storageUsage = *tenant.AddStorageUsage(); - storageUsage.SetType(type); - storageUsage.SetSize(size); auto it = storageQuotasByType.find(type); if (it != storageQuotasByType.end()) { - storageUsage.SetLimit(it->second.HardQuota); - storageUsage.SetSoftQuota(it->second.SoftQuota); - storageUsage.SetHardQuota(it->second.HardQuota); + auto& tabletStorage = *tenant.AddTabletStorage(); + tabletStorage.SetType(type); + tabletStorage.SetSize(size); + tabletStorage.SetLimit(it->second.SoftQuota); + tabletStorage.SetSoftQuota(it->second.SoftQuota); + tabletStorage.SetHardQuota(it->second.HardQuota); } } + + for (const auto& [type, size] : blobStorageByType) { + auto& databaseStorage = *tenant.AddDatabaseStorage(); + databaseStorage.SetType(type); + databaseStorage.SetSize(size); + } } THashSet tenantNodes;