aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorserg-belyakov <serg-belyakov@yandex-team.com>2023-03-22 16:59:57 +0300
committerserg-belyakov <serg-belyakov@yandex-team.com>2023-03-22 16:59:57 +0300
commit73c011f083796aacb2d4f07b363248794ae94d6c (patch)
treecc8e5b798ba7fad731405e18ec206e473c63710b
parentabb4e4900922ac55e05c07b6fd9a81f56167cd12 (diff)
downloadydb-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.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