diff options
author | serg-belyakov <serg-belyakov@yandex-team.com> | 2023-03-22 16:59:57 +0300 |
---|---|---|
committer | serg-belyakov <serg-belyakov@yandex-team.com> | 2023-03-22 16:59:57 +0300 |
commit | 73c011f083796aacb2d4f07b363248794ae94d6c (patch) | |
tree | cc8e5b798ba7fad731405e18ec206e473c63710b | |
parent | abb4e4900922ac55e05c07b6fd9a81f56167cd12 (diff) | |
download | ydb-73c011f083796aacb2d4f07b363248794ae94d6c.tar.gz |
Add diagnostic information about GroupLayoutSanitizer to SelfHeal actor HTTP page,
Check group layout on updating group info in SelfHeal
Add GroupWithInvalidLayout diagnostics in self heal http page
-rw-r--r-- | ydb/core/blobstorage/ut_blobstorage/sanitize_groups.cpp | 8 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt | 1 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt | 1 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt | 1 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt | 1 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/bsc.cpp | 7 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/impl.h | 6 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/layout_helpers.cpp | 110 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/layout_helpers.h | 25 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/self_heal.cpp | 177 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/types.h | 3 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/ut_layout_helpers.h | 114 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/ut_selfheal/main.cpp | 6 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp | 5 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/ya.make | 2 |
15 files changed, 331 insertions, 136 deletions
diff --git a/ydb/core/blobstorage/ut_blobstorage/sanitize_groups.cpp b/ydb/core/blobstorage/ut_blobstorage/sanitize_groups.cpp index 4ad388e5ffb..f942746626c 100644 --- a/ydb/core/blobstorage/ut_blobstorage/sanitize_groups.cpp +++ b/ydb/core/blobstorage/ut_blobstorage/sanitize_groups.cpp @@ -1,5 +1,5 @@ #include <ydb/core/blobstorage/ut_blobstorage/lib/env.h> -#include <ydb/core/mind/bscontroller/ut_layout_helpers.h> +#include <ydb/core/mind/bscontroller/layout_helpers.h> Y_UNIT_TEST_SUITE(GroupLayoutSanitizer) { @@ -44,19 +44,19 @@ Y_UNIT_TEST_SUITE(GroupLayoutSanitizer) { TString error; auto cfg = env.FetchBaseConfig(); - UNIT_ASSERT_C(CheckGroupLayout(geom, cfg, error), error); + UNIT_ASSERT_C(CheckBaseConfigLayout(geom, cfg, error), error); env.Cleanup(); std::random_shuffle(locations.begin(), locations.end()); env.Initialize(); env.Sim(TDuration::Seconds(100)); cfg = env.FetchBaseConfig(); - CheckGroupLayout(geom, cfg, error); + CheckBaseConfigLayout(geom, cfg, error); Cerr << error << Endl; env.UpdateSettings(true, false, true); env.Sim(TDuration::Minutes(15)); cfg = env.FetchBaseConfig(); - UNIT_ASSERT_C(CheckGroupLayout(geom, cfg, error), error); + UNIT_ASSERT_C(CheckBaseConfigLayout(geom, cfg, error), error); } } diff --git a/ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt b/ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt index 29efd0a4070..01fee7db2e2 100644 --- a/ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt +++ b/ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt @@ -47,6 +47,7 @@ target_sources(core-mind-bscontroller PRIVATE ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_metrics_exchange.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_reconfigure_wipe.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/init_scheme.cpp + ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/layout_helpers.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/load_everything.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/migrate.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/monitoring.cpp diff --git a/ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt b/ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt index a7dfc9839c0..1b4f0596aa4 100644 --- a/ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt +++ b/ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt @@ -48,6 +48,7 @@ target_sources(core-mind-bscontroller PRIVATE ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_metrics_exchange.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_reconfigure_wipe.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/init_scheme.cpp + ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/layout_helpers.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/load_everything.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/migrate.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/monitoring.cpp diff --git a/ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt b/ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt index a7dfc9839c0..1b4f0596aa4 100644 --- a/ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt +++ b/ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt @@ -48,6 +48,7 @@ target_sources(core-mind-bscontroller PRIVATE ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_metrics_exchange.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_reconfigure_wipe.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/init_scheme.cpp + ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/layout_helpers.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/load_everything.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/migrate.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/monitoring.cpp diff --git a/ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt b/ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt index 29efd0a4070..01fee7db2e2 100644 --- a/ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt +++ b/ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt @@ -47,6 +47,7 @@ target_sources(core-mind-bscontroller PRIVATE ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_metrics_exchange.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/group_reconfigure_wipe.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/init_scheme.cpp + ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/layout_helpers.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/load_everything.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/migrate.cpp ${CMAKE_SOURCE_DIR}/ydb/core/mind/bscontroller/monitoring.cpp diff --git a/ydb/core/mind/bscontroller/bsc.cpp b/ydb/core/mind/bscontroller/bsc.cpp index 1e23c67ef0f..96e42db2b59 100644 --- a/ydb/core/mind/bscontroller/bsc.cpp +++ b/ydb/core/mind/bscontroller/bsc.cpp @@ -117,9 +117,6 @@ void TBlobStorageController::OnActivateExecutor(const TActorContext&) { } } - // create self-heal actor - SelfHealId = Register(CreateSelfHealActor()); - // create stat processor StatProcessorActorId = Register(CreateStatProcessorActor()); @@ -154,10 +151,12 @@ void TBlobStorageController::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev) { const bool initial = !HostRecords; HostRecords = std::make_shared<THostRecordMap::element_type>(ev->Get()); Schedule(TDuration::Minutes(5), new TEvPrivate::TEvHostRecordsTimeToLiveExceeded); - Send(SelfHealId, new TEvPrivate::TEvUpdateHostRecords(HostRecords)); if (initial) { + // create self-heal actor + SelfHealId = Register(CreateSelfHealActor()); Execute(CreateTxInitScheme()); } + Send(SelfHealId, new TEvPrivate::TEvUpdateHostRecords(HostRecords)); } void TBlobStorageController::HandleHostRecordsTimeToLiveExceeded() { diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h index 909da0b9600..7c2db5bd557 100644 --- a/ydb/core/mind/bscontroller/impl.h +++ b/ydb/core/mind/bscontroller/impl.h @@ -1691,6 +1691,12 @@ public: return GroupLayoutSanitizer; } + // For test purposes, required for self heal actor + void CreateEmptyHostRecordsMap() { + TEvInterconnect::TEvNodesInfo nodes; + HostRecords = std::make_shared<THostRecordMapImpl>(&nodes); + } + private: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Online state diff --git a/ydb/core/mind/bscontroller/layout_helpers.cpp b/ydb/core/mind/bscontroller/layout_helpers.cpp new file mode 100644 index 00000000000..6db97750b5c --- /dev/null +++ b/ydb/core/mind/bscontroller/layout_helpers.cpp @@ -0,0 +1,110 @@ +#include "layout_helpers.h" + +namespace NKikimr { + +namespace NBsController { + +bool CheckLayoutByGroupDefinition(const TGroupMapper::TGroupDefinition& group, + std::unordered_map<TPDiskId, NLayoutChecker::TPDiskLayoutPosition>& pdisks, + const TGroupGeometryInfo& geom, TString& error) { + std::unordered_set<ui32> usedPRealms; + std::set<TPDiskId> usedPDisks; + for (ui32 failRealm = 0; failRealm < geom.GetNumFailRealms(); ++failRealm) { + ui32 pRealm = pdisks[group[failRealm][0][0]].Realm.Index(); + if (usedPRealms.count(pRealm)) { + error = TStringBuilder() << "PRealm intersection, PRealm index# " << pRealm; + return false; + } + usedPRealms.insert(pRealm); + std::unordered_set<ui32> usedPDomains; + for (ui32 failDomain = 0; failDomain < geom.GetNumFailDomainsPerFailRealm(); ++failDomain) { + ui32 pDomain = pdisks[group[failRealm][failDomain][0]].Domain.Index(); + if (usedPDomains.count(pDomain)) { + error = TStringBuilder() << "PDomain intersection, PDomain index# " << pDomain; + return false; + } + usedPDomains.insert(pDomain); + for (ui32 vdisk = 0; vdisk < geom.GetNumVDisksPerFailDomain(); ++vdisk) { + const auto& pdiskId = group[failRealm][failDomain][vdisk]; + if (pdiskId == TPDiskId()) { + error = TStringBuilder() << "empty slot, VSlotId# {FailRealm# " << failRealm << + ", FailDomain# " << failDomain << ", VDisk# " << vdisk << "}"; + return false; + } + + Y_VERIFY(pdisks.find(pdiskId) != pdisks.end()); + if (pdisks[pdiskId].RealmGroup != pdisks[group[0][0][0]].RealmGroup || + pdisks[pdiskId].Realm != pdisks[group[failRealm][0][0]].Realm || + pdisks[pdiskId].Domain != pdisks[group[failRealm][failDomain][0]].Domain) { + error = TStringBuilder() << "bad pdisk placement, VSlotId# {FailRealm# " << failRealm << + ", FailDomain# " << failDomain << ", VDisk# " << vdisk << "}, PDiskId# " << pdiskId.ToString(); + return false; + } + if (usedPDisks.find(pdiskId) != usedPDisks.end()) { + error = TStringBuilder() << "PDisk intersection, #id " << pdiskId.ToString(); + return false; + } + usedPDisks.insert(pdiskId); + } + } + } + + return true; +} + +bool CheckBaseConfigLayout(const TGroupGeometryInfo& geom, const NKikimrBlobStorage::TBaseConfig& cfg, TString& error) { + NLayoutChecker::TDomainMapper domainMapper; + + std::unordered_map<ui32, TNodeLocation> nodes; + std::unordered_map<TPDiskId, NLayoutChecker::TPDiskLayoutPosition> pdisks; + + for (ui32 i = 0; i < cfg.NodeSize(); ++i) { + auto node = cfg.GetNode(i); + nodes[node.GetNodeId()] = TNodeLocation(node.GetLocation()); + } + + for (ui32 i = 0; i < cfg.PDiskSize(); ++i) { + auto pdisk = cfg.GetPDisk(i); + TNodeLocation loc = nodes[pdisk.GetNodeId()]; + TPDiskId pdiskId(pdisk.GetNodeId(), pdisk.GetPDiskId()); + pdisks[pdiskId] = NLayoutChecker::TPDiskLayoutPosition(domainMapper, loc, pdiskId, geom); + } + + std::unordered_map<ui32, TGroupMapper::TGroupDefinition> groups; + for (ui32 i = 0; i < cfg.VSlotSize(); ++i) { + auto vslot = cfg.GetVSlot(i); + TPDiskId pdiskId(vslot.GetVSlotId().GetNodeId(), vslot.GetVSlotId().GetPDiskId()); + Y_VERIFY(pdiskId != TPDiskId()); + Y_VERIFY(pdisks.find(pdiskId) != pdisks.end()); + ui32 groupId = vslot.GetGroupId(); + geom.ResizeGroup(groups[groupId]); + groups[groupId][vslot.GetFailRealmIdx()][vslot.GetFailDomainIdx()][vslot.GetVDiskIdx()] = pdiskId; + } + + for (auto& [groupId, group] : groups) { + TString layoutError; + if (!CheckLayoutByGroupDefinition(group, pdisks, geom, layoutError)) { + error = TStringBuilder() << "GroupId# " << groupId << " " << layoutError; + return false; + } + } + + return true; +} + +TGroupGeometryInfo CreateGroupGeometry(TBlobStorageGroupType type, ui32 numFailRealms, ui32 numFailDomains, + ui32 numVDisks, ui32 realmBegin, ui32 realmEnd, ui32 domainBegin, ui32 domainEnd) { + NKikimrBlobStorage::TGroupGeometry g; + g.SetNumFailRealms(numFailRealms); + g.SetNumFailDomainsPerFailRealm(numFailDomains); + g.SetNumVDisksPerFailDomain(numVDisks); + g.SetRealmLevelBegin(realmBegin); + g.SetRealmLevelEnd(realmEnd); + g.SetDomainLevelBegin(domainBegin); + g.SetDomainLevelEnd(domainEnd); + return TGroupGeometryInfo(type, g); +} + +} // namespace NBsController + +} // namespace NKikimr diff --git a/ydb/core/mind/bscontroller/layout_helpers.h b/ydb/core/mind/bscontroller/layout_helpers.h new file mode 100644 index 00000000000..69490b84efb --- /dev/null +++ b/ydb/core/mind/bscontroller/layout_helpers.h @@ -0,0 +1,25 @@ +#pragma once + +#include "defs.h" + +#include <ydb/core/mind/bscontroller/group_layout_checker.h> +#include <ydb/core/mind/bscontroller/group_mapper.h> +#include <ydb/core/mind/bscontroller/group_geometry_info.h> +#include <ydb/core/mind/bscontroller/types.h> + +namespace NKikimr { + +namespace NBsController { + +bool CheckLayoutByGroupDefinition(const TGroupMapper::TGroupDefinition& group, + std::unordered_map<TPDiskId, NLayoutChecker::TPDiskLayoutPosition>& pdisks, + const TGroupGeometryInfo& geom, TString& error); + +bool CheckBaseConfigLayout(const TGroupGeometryInfo& geom, const NKikimrBlobStorage::TBaseConfig& cfg, TString& error); + +TGroupGeometryInfo CreateGroupGeometry(TBlobStorageGroupType type, ui32 numFailRealms = 0, ui32 numFailDomains = 0, + ui32 numVDisks = 0, ui32 realmBegin = 0, ui32 realmEnd = 0, ui32 domainBegin = 0, ui32 domainEnd = 0); + +} // namespace NBsController + +} // namespace NKikimr diff --git a/ydb/core/mind/bscontroller/self_heal.cpp b/ydb/core/mind/bscontroller/self_heal.cpp index 336630a404b..bdf537f7309 100644 --- a/ydb/core/mind/bscontroller/self_heal.cpp +++ b/ydb/core/mind/bscontroller/self_heal.cpp @@ -4,6 +4,7 @@ #include "config.h" #include "group_geometry_info.h" #include "group_layout_checker.h" +#include "layout_helpers.h" namespace NKikimr::NBsController { @@ -237,7 +238,9 @@ namespace NKikimr::NBsController { TDuration RetryTimeout = MinRetryTimeout; TInstant NextRetryTimestamp = TInstant::Zero(); THashMap<TVDiskID, TVDiskStatusTracker> VDiskStatus; - bool LayoutValid = false; + + bool LayoutValid = true; + TString LayoutError; TGroupRecord(TGroupId groupId) : GroupId(groupId) {} }; @@ -251,16 +254,26 @@ namespace NKikimr::NBsController { bool GroupLayoutSanitizer = false; THostRecordMap HostRecords; + enum EPeriodicProcess { + SELF_HEAL = 0, + GROUP_LAYOUT_SANITIZER, + }; + + static constexpr TDuration SelfHealWakeupPeriod = TDuration::Seconds(10); + static constexpr TDuration GroupLayoutSanitizerWakeupPeriod = TDuration::Seconds(60); + public: - TSelfHealActor(ui64 tabletId, std::shared_ptr<std::atomic_uint64_t> unreassignableGroups) + TSelfHealActor(ui64 tabletId, std::shared_ptr<std::atomic_uint64_t> unreassignableGroups, THostRecordMap hostRecords) : TabletId(tabletId) , UnreassignableGroups(std::move(unreassignableGroups)) + , HostRecords(std::move(hostRecords)) {} void Bootstrap(const TActorId& parentId) { ControllerId = parentId; Become(&TThis::StateFunc); - HandleWakeup(); + HandleWakeup(EPeriodicProcess::SELF_HEAL); + HandleWakeup(EPeriodicProcess::GROUP_LAYOUT_SANITIZER); } void Handle(TEvControllerUpdateSelfHealInfo::TPtr& ev) { @@ -273,9 +286,13 @@ namespace NKikimr::NBsController { const auto [it, inserted] = Groups.try_emplace(groupId, groupId); auto& g = it->second; bool hasFaultyDisks = false; + g.Content = std::move(*data); - g.LayoutValid = false; - GroupsWithInvalidLayout.PushBack(&g); + + if (GroupLayoutSanitizer) { + UpdateGroupLayoutInformation(g); + } + for (const auto& [vdiskId, vdisk] : g.Content.VDisks) { g.VDiskStatus[vdiskId].Update(vdisk.VDiskStatus, now); hasFaultyDisks |= vdisk.Faulty; @@ -355,6 +372,43 @@ namespace NKikimr::NBsController { UnreassignableGroups->store(counter); } + void UpdateGroupLayoutInformation(TGroupRecord& group) { + NLayoutChecker::TDomainMapper domainMapper; + Y_VERIFY(group.Content.Geometry); + Y_VERIFY(HostRecords); + auto groupDef = MakeGroupDefinition(group.Content.VDisks, *group.Content.Geometry); + + std::unordered_map<TPDiskId, NLayoutChecker::TPDiskLayoutPosition> pdisks; + for (const auto& [vdiskId, vdisk] : group.Content.VDisks) { + ui32 nodeId = vdisk.Location.NodeId; + TPDiskId pdiskId = vdisk.Location.ComprisingPDiskId(); + if (HostRecords->GetHostId(nodeId)) { + pdisks[pdiskId] = NLayoutChecker::TPDiskLayoutPosition(domainMapper, + HostRecords->GetLocation(nodeId), + pdiskId, + *group.Content.Geometry); + } else { + // Node location cannot be obtained, assume group layout is valid + return; + } + } + + TString error; + bool isValid = CheckLayoutByGroupDefinition(groupDef, + pdisks, + *group.Content.Geometry, + error); + + if (group.LayoutValid && !isValid) { + group.LayoutError = error; + GroupsWithInvalidLayout.PushBack(&group); + } else if (!group.LayoutValid && isValid) { + group.LayoutError.clear(); + GroupsWithInvalidLayout.Remove(&group); + } + group.LayoutValid = isValid; + } + std::optional<TVDiskID> FindVDiskToReplace(const THashMap<TVDiskID, TVDiskStatusTracker>& tracker, const TEvControllerUpdateSelfHealInfo::TGroupContent& content, TInstant now) { auto status = [&](const TVDiskID& id) { @@ -402,7 +456,7 @@ namespace NKikimr::NBsController { CheckGroups(); } } - + using TVDiskInfo = TEvControllerUpdateSelfHealInfo::TGroupContent::TVDiskInfo; TGroupMapper::TGroupDefinition MakeGroupDefinition(const TMap<TVDiskID, TVDiskInfo>& vdisks, const TGroupGeometryInfo& geom) { @@ -418,9 +472,26 @@ namespace NKikimr::NBsController { return std::move(groupDefinition); } - void HandleWakeup() { - CheckGroups(); - Schedule(TDuration::Seconds(10), new TEvents::TEvWakeup); + void HandleWakeup(EPeriodicProcess process) { + switch (process) { + case EPeriodicProcess::SELF_HEAL: + CheckGroups(); + Schedule(SelfHealWakeupPeriod, new TEvents::TEvWakeup(EPeriodicProcess::SELF_HEAL)); + break; + + case EPeriodicProcess::GROUP_LAYOUT_SANITIZER: + if (GroupLayoutSanitizer) { + for (auto& [_, group] : Groups) { + UpdateGroupLayoutInformation(group); + } + } + Schedule(GroupLayoutSanitizerWakeupPeriod, new TEvents::TEvWakeup(EPeriodicProcess::GROUP_LAYOUT_SANITIZER)); + break; + } + } + + void Handle(TEvents::TEvWakeup::TPtr& ev) { + HandleWakeup(EPeriodicProcess(ev->Get()->Tag)); } void Handle(NMon::TEvRemoteHttpInfo::TPtr& ev) { @@ -557,6 +628,89 @@ namespace NKikimr::NBsController { } } } + + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { + out << "Group Layout Sanitizer"; + } + DIV_CLASS("panel-body") { + out << "Status: " << (GroupLayoutSanitizer ? "enabled" : "disabled"); + } + } + + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { + out << "Groups with invalid layout"; + } + DIV_CLASS("panel-body") { + TABLE_CLASS("table-sortable table") { + TABLEHEAD() { + ui32 numCols = 0; + for (const TGroupRecord& group : GroupsWithInvalidLayout) { + numCols = Max<ui32>(numCols, group.Content.VDisks.size()); + } + + TABLER() { + TABLEH() { out << "GroupId:Gen"; } + for (ui32 i = 0; i < numCols; ++i) { + TABLEH() { out << "OrderNum# " << i; } + } + TABLEH() { out << "LayoutErrorReason# "; } + } + } + TABLEBODY() { + for (const TGroupRecord& group : GroupsWithInvalidLayout) { + TABLER() { + out << "<td rowspan='2'><a href='?TabletID=" << TabletId + << "&page=GroupDetail&GroupId=" << group.GroupId << "'>" + << group.GroupId << "</a>:" << group.Content.Generation << "</td>"; + + for (const auto& [vdiskId, vdisk] : group.Content.VDisks) { + TABLED() { + out << vdiskId.ToString(); + out << "<br/>"; + out << vdisk.VDiskStatus; + out << "<br/><strong>"; + if (const auto it = group.VDiskStatus.find(vdiskId); it != group.VDiskStatus.end()) { + if (const auto& status = it->second.GetStatus(now)) { + out << *status; + } else { + out << "unsure"; + } + } else { + out << "?"; + } + out << "</strong>"; + } + } + + out << "<td rowspan='2'>" << group.LayoutError << "</td>"; + } + TABLER() { + for (const auto& [vdiskId, vdisk] : group.Content.VDisks) { + TABLED() { + const auto& l = vdisk.Location; + if (vdisk.Faulty) { + out << "<strong>"; + } + if (vdisk.Bad) { + out << "<font color='red'>"; + } + out << "[" << l.NodeId << ":" << l.PDiskId << ":" << l.VSlotId << "]"; + if (vdisk.Bad) { + out << "</font>"; + } + if (vdisk.Faulty) { + out << "</strong>"; + } + } + } + } + } + } + } + } + } } } @@ -569,13 +723,14 @@ namespace NKikimr::NBsController { hFunc(TEvControllerUpdateSelfHealInfo, Handle); hFunc(NMon::TEvRemoteHttpInfo, Handle); hFunc(TEvReassignerDone, Handle); - cFunc(TEvents::TSystem::Wakeup, HandleWakeup); + hFunc(TEvents::TEvWakeup, Handle); hFunc(TEvPrivate::TEvUpdateHostRecords, Handle); }) }; IActor *TBlobStorageController::CreateSelfHealActor() { - return new TSelfHealActor(TabletID(), SelfHealUnreassignableGroups); + Y_VERIFY(HostRecords); + return new TSelfHealActor(TabletID(), SelfHealUnreassignableGroups, HostRecords); } void TBlobStorageController::InitializeSelfHealState() { diff --git a/ydb/core/mind/bscontroller/types.h b/ydb/core/mind/bscontroller/types.h index 83eca1e4760..c864cf8ae1d 100644 --- a/ydb/core/mind/bscontroller/types.h +++ b/ydb/core/mind/bscontroller/types.h @@ -419,6 +419,9 @@ inline size_t THash<NKikimr::NBsController::TPDiskId>::operator ()(NKikimr::NBsC return THash<T>()(key); } +template<> +struct std::hash<NKikimr::NBsController::TPDiskId> : THash<NKikimr::NBsController::TPDiskId> {}; + inline size_t THash<NKikimr::NBsController::TVSlotId>::operator ()(NKikimr::NBsController::TVSlotId x) const { auto key = x.GetKey(); using T = decltype(key); diff --git a/ydb/core/mind/bscontroller/ut_layout_helpers.h b/ydb/core/mind/bscontroller/ut_layout_helpers.h deleted file mode 100644 index d5904917169..00000000000 --- a/ydb/core/mind/bscontroller/ut_layout_helpers.h +++ /dev/null @@ -1,114 +0,0 @@ -#include "defs.h" - -#include <ydb/core/mind/bscontroller/group_layout_checker.h> -#include <ydb/core/mind/bscontroller/group_mapper.h> -#include <ydb/core/mind/bscontroller/group_geometry_info.h> - - -bool CheckGroupLayout(const TGroupGeometryInfo& geom, const NKikimrBlobStorage::TBaseConfig& cfg, TString& error) { - static NLayoutChecker::TDomainMapper domainMapper; - - std::map<ui32, TNodeLocation> nodes; - std::map<TPDiskId, NLayoutChecker::TPDiskLayoutPosition> pdisks; - - for (ui32 i = 0; i < cfg.NodeSize(); ++i) { - auto node = cfg.GetNode(i); - nodes[node.GetNodeId()] = TNodeLocation(node.GetLocation()); - } - - for (ui32 i = 0; i < cfg.PDiskSize(); ++i) { - auto pdisk = cfg.GetPDisk(i); - TNodeLocation loc = nodes[pdisk.GetNodeId()]; - TPDiskId pdiskId(pdisk.GetNodeId(), pdisk.GetPDiskId()); - pdisks[pdiskId] = NLayoutChecker::TPDiskLayoutPosition(domainMapper, loc, pdiskId, geom); - } - - std::unordered_map<ui32, TGroupMapper::TGroupDefinition> groups; - bool status = true; - for (ui32 i = 0; i < cfg.VSlotSize(); ++i) { - auto vslot = cfg.GetVSlot(i); - TPDiskId pdiskId(vslot.GetVSlotId().GetNodeId(), vslot.GetVSlotId().GetPDiskId()); - Y_VERIFY(pdiskId != TPDiskId()); - Y_VERIFY(pdisks.find(pdiskId) != pdisks.end()); - ui32 groupId = vslot.GetGroupId(); - geom.ResizeGroup(groups[groupId]); - groups[groupId][vslot.GetFailRealmIdx()][vslot.GetFailDomainIdx()][vslot.GetVDiskIdx()] = pdiskId; - } - - for (auto& [groupId, group] : groups) { - std::unordered_set<ui32> usedPRealms; - std::set<TPDiskId> usedPDisks; - TStringStream g; - g << "GroupId# " << groupId << ", Group# "; - for (ui32 failRealm = 0; failRealm < geom.GetNumFailRealms(); ++failRealm) { - g << "["; - ui32 pRealm = pdisks[group[failRealm][0][0]].Realm.Index(); - if (usedPRealms.count(pRealm)) { - if (!status) { - error = TStringBuilder() << "PRealm intersection, PRealm index# " << pRealm; - } - status = false; - } - usedPRealms.insert(pRealm); - std::unordered_set<ui32> usedPDomains; - for (ui32 failDomain = 0; failDomain < geom.GetNumFailDomainsPerFailRealm(); ++failDomain) { - g << "["; - ui32 pDomain = pdisks[group[failRealm][failDomain][0]].Domain.Index(); - if (usedPDomains.count(pDomain)) { - error = TStringBuilder() << "PDomain intersection, PDomain index# " << pDomain; - status = false; - } - usedPDomains.insert(pDomain); - for (ui32 vdisk = 0; vdisk < geom.GetNumVDisksPerFailDomain(); ++vdisk) { - - TString vslot = TStringBuilder() << "VSlot# {FailRealm# " << failRealm << - ", FailDomain# " << failDomain << ", vdisk# " << vdisk << "}"; - - const auto& pdiskId = group[failRealm][failDomain][vdisk]; - if (pdiskId == TPDiskId()) { - error = vslot + ", empty slot"; - status = false; - } - - g << group[failRealm][failDomain][vdisk].ToString() << '=' << pdisks[pdiskId].RealmGroup << '/' << - pdisks[pdiskId].Realm << '/' << pdisks[pdiskId].Domain; - - Y_VERIFY(pdisks.find(pdiskId) != pdisks.end()); - if (pdisks[pdiskId].RealmGroup != pdisks[group[0][0][0]].RealmGroup || - pdisks[pdiskId].Realm != pdisks[group[failRealm][0][0]].Realm || - pdisks[pdiskId].Domain != pdisks[group[failRealm][failDomain][0]].Domain) { - error = TStringBuilder() << vslot << ", bad pdisk placement, PDiskId# " << pdiskId; - status = false; - } - if (usedPDisks.find(pdiskId) != usedPDisks.end()) { - error = TStringBuilder() << "PDisk intersection, #id " << pdiskId.ToString(); - status = false; - } - usedPDisks.insert(pdiskId); - } - g << "]"; - } - g << "]"; - } - - if (!status) { - error += ", GroupLayout# " + g.Str(); - return false; - } - } - - return true; -} - -TGroupGeometryInfo CreateGroupGeometry(TBlobStorageGroupType type, ui32 numFailRealms = 0, ui32 numFailDomains = 0, - ui32 numVDisks = 0, ui32 realmBegin = 0, ui32 realmEnd = 0, ui32 domainBegin = 0, ui32 domainEnd = 0) { - NKikimrBlobStorage::TGroupGeometry g; - g.SetNumFailRealms(numFailRealms); - g.SetNumFailDomainsPerFailRealm(numFailDomains); - g.SetNumVDisksPerFailDomain(numVDisks); - g.SetRealmLevelBegin(realmBegin); - g.SetRealmLevelEnd(realmEnd); - g.SetDomainLevelBegin(domainBegin); - g.SetDomainLevelEnd(domainEnd); - return TGroupGeometryInfo(type, g); -} diff --git a/ydb/core/mind/bscontroller/ut_selfheal/main.cpp b/ydb/core/mind/bscontroller/ut_selfheal/main.cpp index 8a608378f3e..5ebe215be17 100644 --- a/ydb/core/mind/bscontroller/ut_selfheal/main.cpp +++ b/ydb/core/mind/bscontroller/ut_selfheal/main.cpp @@ -4,7 +4,7 @@ #include "env.h" -#include <ydb/core/mind/bscontroller/ut_layout_helpers.h> +#include <ydb/core/mind/bscontroller/layout_helpers.h> Y_UNIT_TEST_SUITE(BsControllerTest) { @@ -53,7 +53,7 @@ Y_UNIT_TEST_SUITE(BsControllerTest) { } TString error; - UNIT_ASSERT_C(CheckGroupLayout(geom, response.GetStatus(0).GetBaseConfig(), error), "Initial group layout is incorrect, ErrorReason# " + UNIT_ASSERT_C(CheckBaseConfigLayout(geom, response.GetStatus(0).GetBaseConfig(), error), "Initial group layout is incorrect, ErrorReason# " << error); UNIT_ASSERT_VALUES_EQUAL(active.size(), numNodes * numDisksPerNode); @@ -111,7 +111,7 @@ Y_UNIT_TEST_SUITE(BsControllerTest) { UNIT_FAIL("non-active disk is present in group"); } } - UNIT_ASSERT_C(CheckGroupLayout(geom, response.GetStatus(0).GetBaseConfig(), error), "Error on step# " << i + UNIT_ASSERT_C(CheckBaseConfigLayout(geom, response.GetStatus(0).GetBaseConfig(), error), "Error on step# " << i << ", ErrorReason# " << error); } } diff --git a/ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp b/ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp index 2bb0cddf02a..5867afd514b 100644 --- a/ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp +++ b/ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp @@ -2,6 +2,7 @@ #include <ydb/core/util/testactorsys.h> #include <ydb/core/mind/bscontroller/self_heal.h> #include <ydb/core/mind/bscontroller/impl.h> +#include <ydb/core/mind/bscontroller/layout_helpers.h> using namespace NActors; using namespace NKikimr; @@ -15,7 +16,10 @@ void RunTestCase(TCallback&& callback) { runtime.Start(); const TActorId& parentId = runtime.AllocateEdgeActor(1); TBlobStorageController Controller({}, new TTabletStorageInfo(1, TTabletTypes::BSController)); + + Controller.CreateEmptyHostRecordsMap(); const TActorId& selfHealId = runtime.Register(Controller.CreateSelfHealActor(), parentId, {}, {}, 1); + callback(selfHealId, parentId, runtime); runtime.Stop(); } @@ -55,6 +59,7 @@ TEvControllerUpdateSelfHealInfo::TGroupContent Convert(const TIntrusivePtr<TBlob TEvControllerUpdateSelfHealInfo::TGroupContent res; res.Generation = info->GroupGeneration; res.Type = info->Type; + res.Geometry = std::make_shared<TGroupGeometryInfo>(CreateGroupGeometry(TBlobStorageGroupType::Erasure4Plus2Block)); for (ui32 i = 0; i < info->GetTotalVDisksNum(); ++i) { auto& x = res.VDisks[info->GetVDiskId(i)]; x.Location = {1, 1000 + i, 1000}; diff --git a/ydb/core/mind/bscontroller/ya.make b/ydb/core/mind/bscontroller/ya.make index b32cadcb30c..b9bf78ca9c5 100644 --- a/ydb/core/mind/bscontroller/ya.make +++ b/ydb/core/mind/bscontroller/ya.make @@ -29,6 +29,8 @@ SRCS( impl.h indir.h init_scheme.cpp + layout_helpers.h + layout_helpers.cpp load_everything.cpp migrate.cpp monitoring.cpp |