summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorserg-belyakov <[email protected]>2023-03-22 16:59:57 +0300
committerserg-belyakov <[email protected]>2023-03-22 16:59:57 +0300
commit73c011f083796aacb2d4f07b363248794ae94d6c (patch)
treecc8e5b798ba7fad731405e18ec206e473c63710b
parentabb4e4900922ac55e05c07b6fd9a81f56167cd12 (diff)
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.cpp8
-rw-r--r--ydb/core/mind/bscontroller/CMakeLists.darwin-x86_64.txt1
-rw-r--r--ydb/core/mind/bscontroller/CMakeLists.linux-aarch64.txt1
-rw-r--r--ydb/core/mind/bscontroller/CMakeLists.linux-x86_64.txt1
-rw-r--r--ydb/core/mind/bscontroller/CMakeLists.windows-x86_64.txt1
-rw-r--r--ydb/core/mind/bscontroller/bsc.cpp7
-rw-r--r--ydb/core/mind/bscontroller/impl.h6
-rw-r--r--ydb/core/mind/bscontroller/layout_helpers.cpp110
-rw-r--r--ydb/core/mind/bscontroller/layout_helpers.h25
-rw-r--r--ydb/core/mind/bscontroller/self_heal.cpp177
-rw-r--r--ydb/core/mind/bscontroller/types.h3
-rw-r--r--ydb/core/mind/bscontroller/ut_layout_helpers.h114
-rw-r--r--ydb/core/mind/bscontroller/ut_selfheal/main.cpp6
-rw-r--r--ydb/core/mind/bscontroller/ut_selfheal/self_heal_actor_ut.cpp5
-rw-r--r--ydb/core/mind/bscontroller/ya.make2
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