summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf.h30
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_generate.cpp100
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_invoke_static_group.cpp27
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_ut.cpp51
-rw-r--r--ydb/core/mind/bscontroller/self_heal.cpp1
-rw-r--r--ydb/core/protos/blobstorage_distributed_config.proto1
6 files changed, 135 insertions, 75 deletions
diff --git a/ydb/core/blobstorage/nodewarden/distconf.h b/ydb/core/blobstorage/nodewarden/distconf.h
index 07d86b3ca0c..a194af1a701 100644
--- a/ydb/core/blobstorage/nodewarden/distconf.h
+++ b/ydb/core/blobstorage/nodewarden/distconf.h
@@ -476,17 +476,25 @@ namespace NKikimr::NStorage {
std::optional<TString> GenerateFirstConfig(NKikimrBlobStorage::TStorageConfig *config, const TString& selfAssemblyUUID);
- void AllocateStaticGroup(NKikimrBlobStorage::TStorageConfig *config, TGroupId groupId, ui32 groupGeneration,
- TBlobStorageGroupType gtype, const NKikimrBlobStorage::TGroupGeometry& geometry,
- const NProtoBuf::RepeatedPtrField<NKikimrBlobStorage::TPDiskFilter>& pdiskFilters,
- std::optional<NKikimrBlobStorage::EPDiskType> pdiskType,
- THashMap<TVDiskIdShort, NBsController::TPDiskId> replacedDisks,
- const NBsController::TGroupMapper::TForbiddenPDisks& forbid,
- i64 requiredSpace, NKikimrBlobStorage::TBaseConfig *baseConfig,
- bool convertToDonor, bool ignoreVSlotQuotaCheck, bool isSelfHealReasonDecommit, TBridgePileId bridgePileId,
- std::optional<TGroupId> bridgeProxyGroupId,
- const NProtoBuf::RepeatedField<ui32>& selfHealAllowedNodes = {},
- bool applyNodeAllowList = false);
+ struct TAllocateStaticGroupParams {
+ NKikimrBlobStorage::TStorageConfig *Config = nullptr;
+ TGroupId GroupId;
+ ui32 GroupGeneration = 0;
+ TBlobStorageGroupType GroupType;
+ THashMap<TVDiskIdShort, NBsController::TPDiskId> ReplacedDisks;
+ NBsController::TGroupMapper::TForbiddenPDisks ForbiddenPDisks;
+ i64 RequiredSpace = 0;
+ const NKikimrBlobStorage::TBaseConfig *BaseConfig = nullptr;
+ bool ConvertToDonor = false;
+ bool IgnoreVSlotQuotaCheck = false;
+ bool AllowUnusableDisks = false;
+ bool IsSelfHealReasonDecommit = false;
+ TBridgePileId BridgePileId;
+ std::optional<TGroupId> BridgeProxyGroupId;
+ bool ApplySelfHealNodeAllowList = false;
+ };
+
+ void AllocateStaticGroup(TAllocateStaticGroupParams params);
bool UpdateConfig(NKikimrBlobStorage::TStorageConfig *config);
diff --git a/ydb/core/blobstorage/nodewarden/distconf_generate.cpp b/ydb/core/blobstorage/nodewarden/distconf_generate.cpp
index 728970e581c..96e83a946b7 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_generate.cpp
+++ b/ydb/core/blobstorage/nodewarden/distconf_generate.cpp
@@ -37,10 +37,15 @@ namespace NKikimr::NStorage {
TGroupId groupId = TGroupId::Zero();
auto allocateGroup = [&](TBridgePileId bridgePileId, std::optional<TGroupId> bridgeProxyGroupId) {
- AllocateStaticGroup(config, groupId, /*groupGeneration=*/ 1, TBlobStorageGroupType(species),
- smConfig.GetGeometry(), smConfig.GetPDiskFilter(),
- smConfig.HasPDiskType() ? std::make_optional(smConfig.GetPDiskType()) : std::nullopt, {}, {}, 0,
- nullptr, false, true, false, bridgePileId, bridgeProxyGroupId);
+ AllocateStaticGroup({
+ .Config = config,
+ .GroupId = groupId,
+ .GroupGeneration = 1,
+ .GroupType = TBlobStorageGroupType(species),
+ .IgnoreVSlotQuotaCheck = true,
+ .BridgePileId = bridgePileId,
+ .BridgeProxyGroupId = bridgeProxyGroupId,
+ });
const auto& groups = config->GetBlobStorageConfig().GetServiceSet().GetGroups();
const auto& allocatedGroup = groups.at(groups.size() - 1);
@@ -144,32 +149,28 @@ namespace NKikimr::NStorage {
return std::nullopt;
}
- void TDistributedConfigKeeper::AllocateStaticGroup(NKikimrBlobStorage::TStorageConfig *config, TGroupId groupId,
- ui32 groupGeneration, TBlobStorageGroupType gtype, const NKikimrBlobStorage::TGroupGeometry& geometry,
- const NProtoBuf::RepeatedPtrField<NKikimrBlobStorage::TPDiskFilter>& pdiskFilters,
- std::optional<NKikimrBlobStorage::EPDiskType> pdiskType,
- THashMap<TVDiskIdShort, NBsController::TPDiskId> replacedDisks,
- const NBsController::TGroupMapper::TForbiddenPDisks& forbid, i64 requiredSpace,
- NKikimrBlobStorage::TBaseConfig *baseConfig, bool convertToDonor, bool ignoreVSlotQuotaCheck,
- bool isSelfHealReasonDecommit, TBridgePileId bridgePileId, std::optional<TGroupId> bridgeProxyGroupId,
- const NProtoBuf::RepeatedField<ui32>& selfHealAllowedNodes, bool applyNodeAllowList) {
+ void TDistributedConfigKeeper::AllocateStaticGroup(TAllocateStaticGroupParams params) {
using TPDiskId = NBsController::TPDiskId;
- NKikimrConfig::TBlobStorageConfig *bsConfig = config->MutableBlobStorageConfig();
+ auto& config = *params.Config;
+ auto& replacedDisks = params.ReplacedDisks;
+ const auto& selfManagementConfig = config.GetSelfManagementConfig();
+ const auto& selfHealAllowedNodes = selfManagementConfig.GetStaticGroupSelfHealAllowedNodes();
+ NKikimrConfig::TBlobStorageConfig *bsConfig = config.MutableBlobStorageConfig();
// build node location map
THashMap<ui32, TNodeLocation> nodeLocations;
THashSet<ui32> allowedNodeIds;
- for (const auto& node : config->GetAllNodes()) {
+ for (const auto& node : config.GetAllNodes()) {
TNodeLocation location(node.GetLocation());
nodeLocations.try_emplace(node.GetNodeId(), location);
- if (bridgePileId == ResolveNodePileId(location)) {
+ if (params.BridgePileId == ResolveNodePileId(location)) {
allowedNodeIds.insert(node.GetNodeId());
}
}
// when restricting self-heal targets, only these node ids may host relocated vdisks
- const bool restrictSelfHealNodes = applyNodeAllowList && !selfHealAllowedNodes.empty();
+ const bool restrictSelfHealNodes = params.ApplySelfHealNodeAllowList && !selfHealAllowedNodes.empty();
const THashSet<ui32> selfHealAllowedNodeSet = restrictSelfHealNodes
? THashSet<ui32>(selfHealAllowedNodes.begin(), selfHealAllowedNodes.end())
: THashSet<ui32>{};
@@ -186,10 +187,10 @@ namespace NKikimr::NStorage {
THashMap<TPDiskId, TPDiskInfo> pdisks;
auto checkMatch = [&](NKikimrBlobStorage::EPDiskType type, bool sharedWithOs, bool readCentric, ui64 kind) {
- if (type == pdiskType) {
+ if (selfManagementConfig.HasPDiskType() && type == selfManagementConfig.GetPDiskType()) {
return true;
}
- for (const auto& pdiskFilter : pdiskFilters) {
+ for (const auto& pdiskFilter : selfManagementConfig.GetPDiskFilter()) {
bool m = true;
for (const auto& p : pdiskFilter.GetProperty()) {
bool pMatch = false;
@@ -223,12 +224,13 @@ namespace NKikimr::NStorage {
ui32 defaultMaxSlots = 16;
- if (baseConfig) {
+ if (params.BaseConfig) {
+ const auto& baseConfig = *params.BaseConfig;
std::optional<NKikimrBlobStorage::TPDiskSpaceColor::E> pdiskSpaceColorBorder;
ui32 pdiskSpaceMarginPromille = 150;
- if (baseConfig->HasSettings()) {
- const auto& settings = baseConfig->GetSettings();
+ if (baseConfig.HasSettings()) {
+ const auto& settings = baseConfig.GetSettings();
if (settings.DefaultMaxSlotsSize()) {
defaultMaxSlots = settings.GetDefaultMaxSlots(0);
}
@@ -240,7 +242,7 @@ namespace NKikimr::NStorage {
}
}
- for (const auto& pdisk : baseConfig->GetPDisk()) {
+ for (const auto& pdisk : baseConfig.GetPDisk()) {
if (!checkMatch(pdisk.GetType(), pdisk.GetSharedWithOs(), pdisk.GetReadCentric(), pdisk.GetKind())) {
continue;
}
@@ -266,13 +268,13 @@ namespace NKikimr::NStorage {
}
const bool usableInTermsOfDecommission =
pdisk.GetDecommitStatus() == NKikimrBlobStorage::EDecommitStatus::DECOMMIT_NONE ||
- pdisk.GetDecommitStatus() == NKikimrBlobStorage::EDecommitStatus::DECOMMIT_REJECTED && !isSelfHealReasonDecommit;
+ pdisk.GetDecommitStatus() == NKikimrBlobStorage::EDecommitStatus::DECOMMIT_REJECTED && !params.IsSelfHealReasonDecommit;
if (!usableInTermsOfDecommission) {
pdiskInfo.Usable = false;
pdiskInfo.WhyUnusable += 'D';
}
- if (!ignoreVSlotQuotaCheck && pdiskInfo.Usable && pdisk.HasPDiskMetrics() && baseConfig->HasSettings()) {
+ if (!params.IgnoreVSlotQuotaCheck && pdiskInfo.Usable && pdisk.HasPDiskMetrics() && baseConfig.HasSettings()) {
const auto& m = pdisk.GetPDiskMetrics();
if (m.HasEnforcedDynamicSlotSize() && pdiskSpaceColorBorder >= NKikimrBlobStorage::TPDiskSpaceColor::YELLOW) {
pdiskInfo.SpaceAvailable = m.GetEnforcedDynamicSlotSize() * (1000 - pdiskSpaceMarginPromille) / 1000;
@@ -287,7 +289,7 @@ namespace NKikimr::NStorage {
}
THashMap<ui32, ui64> maxGroupSlotSize;
- for (const auto& vslot : baseConfig->GetVSlot()) {
+ for (const auto& vslot : baseConfig.GetVSlot()) {
if (vslot.HasVDiskMetrics()) {
if (const auto& m = vslot.GetVDiskMetrics(); m.HasAllocatedSize()) {
ui64& size = maxGroupSlotSize[vslot.GetGroupId()];
@@ -296,7 +298,7 @@ namespace NKikimr::NStorage {
}
}
- for (const auto& vslot : baseConfig->GetVSlot()) {
+ for (const auto& vslot : baseConfig.GetVSlot()) {
const auto& vslotId = vslot.GetVSlotId();
const TPDiskId pdiskId(vslotId.GetNodeId(), vslotId.GetPDiskId());
if (const auto it = pdisks.find(pdiskId); it != pdisks.end()) {
@@ -326,7 +328,7 @@ namespace NKikimr::NStorage {
std::optional<ui32> generation;
for (const auto& group : ss.GetGroups()) {
- if (TGroupId::FromProto(&group, &NKikimrBlobStorage::TGroupInfo::GetGroupID) == groupId) {
+ if (TGroupId::FromProto(&group, &NKikimrBlobStorage::TGroupInfo::GetGroupID) == params.GroupId) {
generation.emplace(group.GetGroupGeneration());
ui32 failRealmIdx = 0;
@@ -367,7 +369,7 @@ namespace NKikimr::NStorage {
for (const auto& vdisk : ss.GetVDisks()) {
const TVDiskID vdiskId = VDiskIDFromVDiskID(vdisk.GetVDiskID());
- if (vdiskId.GroupID == groupId) {
+ if (vdiskId.GroupID == params.GroupId) {
if (!generation) {
throw TExConfigError() << "missing record for group being reconfigured";
} else if (vdiskId.GroupGeneration == *generation && !replacedDisks.contains(vdiskId)) {
@@ -380,10 +382,12 @@ namespace NKikimr::NStorage {
for (const auto& pdisk : ss.GetPDisks()) {
const TPDiskId pdiskId(pdisk.GetNodeID(), pdisk.GetPDiskID());
- if (requiredPDiskIds.contains(pdiskId)) {
+ if (params.AllowUnusableDisks && requiredPDiskIds.contains(pdiskId)) {
if (const auto [it, inserted] = pdisks.try_emplace(pdiskId); inserted) {
- auto& r = it->second.Record;
- r.CopyFrom(pdisk);
+ TPDiskInfo& pdiskInfo = it->second;
+ pdiskInfo.Record.CopyFrom(pdisk);
+ pdiskInfo.Usable = false;
+ pdiskInfo.WhyUnusable += 'X';
}
}
@@ -443,10 +447,10 @@ namespace NKikimr::NStorage {
}
}
};
- EnumerateConfigDrives(*config, 0, processDrive, nullptr, true);
+ EnumerateConfigDrives(config, 0, processDrive, nullptr, true);
// group mapper
- NBsController::TGroupGeometryInfo geom(gtype.GetErasure(), geometry);
+ NBsController::TGroupGeometryInfo geom(params.GroupType.GetErasure(), selfManagementConfig.GetGeometry());
NBsController::TGroupMapper mapper(geom);
for (const auto& [pdiskId, item] : pdisks) {
@@ -465,7 +469,7 @@ namespace NKikimr::NStorage {
slotSizeInUnits = pdiskConfig.GetSlotSizeInUnits();
}
- const bool pileFilter = !bridgePileId || allowedNodeIds.contains(pdiskId.NodeId);
+ const bool pileFilter = !params.BridgePileId || allowedNodeIds.contains(pdiskId.NodeId);
const bool nodeAllowFilter = !restrictSelfHealNodes || selfHealAllowedNodeSet.contains(pdiskId.NodeId);
TString whyUnusable = item.WhyUnusable;
@@ -507,8 +511,8 @@ namespace NKikimr::NStorage {
NBsController::TGroupMapperError error;
const ui32 groupSizeInUnits = 1; // static groups are always single-unit
- if (!mapper.AllocateGroup(groupId.GetRawId(), groupDefinition, replacedDisks, forbid,
- groupSizeInUnits, requiredSpace, false, {}, error)) {
+ if (!mapper.AllocateGroup(params.GroupId.GetRawId(), groupDefinition, replacedDisks,
+ params.ForbiddenPDisks, groupSizeInUnits, params.RequiredSpace, false, {}, error)) {
throw TExConfigError() << "group allocation failed Error# " << error.ErrorMessage
<< " groupDefinition# " << dumpGroupDefinition();
}
@@ -518,38 +522,38 @@ namespace NKikimr::NStorage {
NKikimrBlobStorage::TGroupInfo *sGroup = nullptr;
for (size_t i = 0; i < sSet->GroupsSize(); ++i) {
if (const auto& group = sSet->GetGroups(i); TGroupId::FromProto(&group,
- &NKikimrBlobStorage::TGroupInfo::GetGroupID) == groupId) {
+ &NKikimrBlobStorage::TGroupInfo::GetGroupID) == params.GroupId) {
sGroup = sSet->MutableGroups(i);
break;
}
}
if (!sGroup) {
sGroup = sSet->AddGroups();
- groupId.CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetGroupID);
- sGroup->SetErasureSpecies(gtype.GetErasure());
+ params.GroupId.CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetGroupID);
+ sGroup->SetErasureSpecies(params.GroupType.GetErasure());
} else {
sGroup->ClearRings();
}
- sGroup->SetGroupGeneration(groupGeneration);
+ sGroup->SetGroupGeneration(params.GroupGeneration);
- if (bridgeProxyGroupId) {
- bridgeProxyGroupId->CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetBridgeProxyGroupId);
+ if (params.BridgeProxyGroupId) {
+ params.BridgeProxyGroupId->CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetBridgeProxyGroupId);
}
- bridgePileId.CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetBridgePileId);
+ params.BridgePileId.CopyToProto(sGroup, &NKikimrBlobStorage::TGroupInfo::SetBridgePileId);
THashMap<TVDiskIdShort, NProtoBuf::RepeatedPtrField<NKikimrBlobStorage::TNodeWardenServiceSet::TVDisk::TDonor>> donors;
for (size_t i = 0; i < sSet->VDisksSize(); ++i) {
const auto& vdisk = sSet->GetVDisks(i);
const TVDiskID vdiskId = VDiskIDFromVDiskID(vdisk.GetVDiskID());
- if (vdiskId.GroupID != groupId || vdisk.GetEntityStatus() == NKikimrBlobStorage::EEntityStatus::DESTROY) {
+ if (vdiskId.GroupID != params.GroupId || vdisk.GetEntityStatus() == NKikimrBlobStorage::EEntityStatus::DESTROY) {
continue;
}
auto *m = sSet->MutableVDisks(i);
if (replacedDisks.contains(vdiskId)) {
if (m->HasDonorMode()) {
// this disk is already a donor, nothing to do about it
- } else if (convertToDonor) {
+ } else if (params.ConvertToDonor) {
// make this disk a donor
auto *donorMode = m->MutableDonorMode();
donorMode->SetNumFailRealms(groupDefinition.size());
@@ -565,7 +569,7 @@ namespace NKikimr::NStorage {
donor->MutableVDiskId()->CopyFrom(m->GetVDiskID());
donor->MutableVDiskLocation()->CopyFrom(m->GetVDiskLocation());
} else {
- m->MutableVDiskID()->SetGroupGeneration(groupGeneration);
+ m->MutableVDiskID()->SetGroupGeneration(params.GroupGeneration);
}
}
@@ -601,7 +605,7 @@ namespace NKikimr::NStorage {
sLoc->SetPDiskGuid(pdisk.GetPDiskGuid());
auto *sDisk = sSet->AddVDisks();
- VDiskIDFromVDiskID(TVDiskID(groupId, groupGeneration, vdiskId), sDisk->MutableVDiskID());
+ VDiskIDFromVDiskID(TVDiskID(params.GroupId, params.GroupGeneration, vdiskId), sDisk->MutableVDiskID());
sDisk->SetVDiskKind(NKikimrBlobStorage::TVDiskKind::Default);
sDisk->MutableVDiskLocation()->CopyFrom(*sLoc);
if (const auto it = donors.find(vdiskId); it != donors.end()) {
diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_static_group.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_static_group.cpp
index 30884b3f0cf..fc3e718fe03 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_invoke_static_group.cpp
+++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_static_group.cpp
@@ -176,8 +176,6 @@ namespace NKikimr::NStorage {
}
const auto& ss = bsConfig.GetServiceSet();
- const auto& smConfig = config.GetSelfManagementConfig();
-
THashMap<TVDiskIdShort, NBsController::TPDiskId> replacedDisks;
NBsController::TGroupMapper::TForbiddenPDisks forbid;
for (const auto& vdisk : ss.GetVDisks()) {
@@ -207,14 +205,23 @@ namespace NKikimr::NStorage {
std::optional<TGroupId> bridgeProxyGroupId = group.HasBridgeProxyGroupId()
? std::make_optional(TGroupId::FromProto(&group, &NKikimrBlobStorage::TGroupInfo::GetBridgeProxyGroupId))
: std::nullopt;
- Self->AllocateStaticGroup(&config, vdiskId.GroupID, vdiskId.GroupGeneration + 1,
- TBlobStorageGroupType((TBlobStorageGroupType::EErasureSpecies)group.GetErasureSpecies()),
- smConfig.GetGeometry(), smConfig.GetPDiskFilter(),
- smConfig.HasPDiskType() ? std::make_optional(smConfig.GetPDiskType()) : std::nullopt,
- replacedDisks, forbid, maxSlotSize,
- &BaseConfig.value(), cmd.GetConvertToDonor(), cmd.GetIgnoreVSlotQuotaCheck(),
- cmd.GetIsSelfHealReasonDecommit(), bridgePileId, bridgeProxyGroupId,
- smConfig.GetStaticGroupSelfHealAllowedNodes(), cmd.GetFromSelfHeal());
+ Self->AllocateStaticGroup({
+ .Config = &config,
+ .GroupId = vdiskId.GroupID,
+ .GroupGeneration = vdiskId.GroupGeneration + 1,
+ .GroupType = TBlobStorageGroupType((TBlobStorageGroupType::EErasureSpecies)group.GetErasureSpecies()),
+ .ReplacedDisks = std::move(replacedDisks),
+ .ForbiddenPDisks = std::move(forbid),
+ .RequiredSpace = static_cast<i64>(maxSlotSize),
+ .BaseConfig = &BaseConfig.value(),
+ .ConvertToDonor = cmd.GetConvertToDonor(),
+ .IgnoreVSlotQuotaCheck = cmd.GetIgnoreVSlotQuotaCheck(),
+ .AllowUnusableDisks = cmd.GetAllowUnusableDisks(),
+ .IsSelfHealReasonDecommit = cmd.GetIsSelfHealReasonDecommit(),
+ .BridgePileId = bridgePileId,
+ .BridgeProxyGroupId = bridgeProxyGroupId,
+ .ApplySelfHealNodeAllowList = cmd.GetFromSelfHeal(),
+ });
} catch (const TExConfigError& ex) {
YDB_LOG_NOTICE("ReassignGroupDisk failed to allocate group",
{"marker", "NWDC76"},
diff --git a/ydb/core/blobstorage/nodewarden/distconf_ut.cpp b/ydb/core/blobstorage/nodewarden/distconf_ut.cpp
index 9606d3c75a6..cbb9d93aa45 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_ut.cpp
+++ b/ydb/core/blobstorage/nodewarden/distconf_ut.cpp
@@ -713,6 +713,16 @@ Y_UNIT_TEST_SUITE(TDistconfStaticGroupSelfHealTest) {
}
return result;
}
+
+ void SetPDiskType(ui32 nodeId, NKikimrBlobStorage::EPDiskType type) {
+ for (auto& pdisk : *BaseConfig.MutablePDisk()) {
+ if (pdisk.GetNodeId() == nodeId) {
+ pdisk.SetType(type);
+ return;
+ }
+ }
+ UNIT_FAIL("PDisk not found");
+ }
};
NKikimrBlobStorage::TGroupGeometry Geometry(ui32 numFailDomains) {
@@ -724,16 +734,28 @@ Y_UNIT_TEST_SUITE(TDistconfStaticGroupSelfHealTest) {
}
void Reallocate(TSetup& s, const NProtoBuf::RepeatedField<ui32>& allowedNodeIds, bool applyNodeAllowList,
- i32 erasureSpecies = TBlobStorageGroupType::ErasureNone, ui32 numFailDomains = 1) {
+ i32 erasureSpecies = TBlobStorageGroupType::ErasureNone, ui32 numFailDomains = 1, bool allowUnusableDisks = false) {
+ auto *selfManagementConfig = s.Config.MutableSelfManagementConfig();
+ selfManagementConfig->MutableGeometry()->CopyFrom(Geometry(numFailDomains));
+ selfManagementConfig->SetPDiskType(NKikimrBlobStorage::EPDiskType::ROT);
+ selfManagementConfig->MutableStaticGroupSelfHealAllowedNodes()->CopyFrom(allowedNodeIds);
+
NKikimr::NStorage::TDistributedConfigKeeper keeper(nullptr, nullptr, true);
THashMap<TVDiskIdShort, NBsController::TPDiskId> replacedDisks;
replacedDisks.emplace(TVDiskIdShort(0, 0, 0), NBsController::TPDiskId());
NBsController::TGroupMapper::TForbiddenPDisks forbid;
- keeper.AllocateStaticGroup(&s.Config, TGroupId::FromValue(0), /*groupGeneration=*/ 2,
- TBlobStorageGroupType((TBlobStorageGroupType::EErasureSpecies)erasureSpecies), Geometry(numFailDomains),
- /*pdiskFilters=*/ {}, NKikimrBlobStorage::EPDiskType::ROT, replacedDisks, forbid,
- /*requiredSpace=*/ 0, &s.BaseConfig, /*convertToDonor=*/ false, /*ignoreVSlotQuotaCheck=*/ true,
- /*isSelfHealReasonDecommit=*/ false, TBridgePileId(), std::nullopt, allowedNodeIds, applyNodeAllowList);
+ keeper.AllocateStaticGroup({
+ .Config = &s.Config,
+ .GroupId = TGroupId::FromValue(0),
+ .GroupGeneration = 2,
+ .GroupType = TBlobStorageGroupType((TBlobStorageGroupType::EErasureSpecies)erasureSpecies),
+ .ReplacedDisks = std::move(replacedDisks),
+ .ForbiddenPDisks = std::move(forbid),
+ .BaseConfig = &s.BaseConfig,
+ .IgnoreVSlotQuotaCheck = true,
+ .AllowUnusableDisks = allowUnusableDisks,
+ .ApplySelfHealNodeAllowList = applyNodeAllowList,
+ });
}
NProtoBuf::RepeatedField<ui32> NodeIds(const std::vector<ui32>& nodeIds) {
@@ -812,6 +834,23 @@ Y_UNIT_TEST_SUITE(TDistconfStaticGroupSelfHealTest) {
Reallocate(s, NodeIds({2}), /*applyNodeAllowList=*/ true, TBlobStorageGroupType::Erasure4Plus2Block, /*numFailDomains=*/ 8),
NKikimr::NStorage::TDistributedConfigKeeper::TExConfigError);
}
+
+ Y_UNIT_TEST(Block42RejectsUnusablePreservedPDiskByDefault) {
+ TSetup s = MakeBlock42Setup();
+ s.SetPDiskType(2, NKikimrBlobStorage::EPDiskType::SSD);
+ UNIT_ASSERT_EXCEPTION(
+ Reallocate(s, NodeIds({}), false, TBlobStorageGroupType::Erasure4Plus2Block, /*numFailDomains=*/ 8),
+ NKikimr::NStorage::TDistributedConfigKeeper::TExConfigError);
+ }
+
+ Y_UNIT_TEST(Block42AllowsUnusablePreservedPDiskWhenRequested) {
+ TSetup s = MakeBlock42Setup();
+ s.SetPDiskType(2, NKikimrBlobStorage::EPDiskType::SSD);
+ UNIT_ASSERT_NO_EXCEPTION(
+ Reallocate(s, NodeIds({}), false, TBlobStorageGroupType::Erasure4Plus2Block, /*numFailDomains=*/ 8,
+ /*allowUnusableDisks=*/ true));
+ UNIT_ASSERT_VALUES_EQUAL(s.GetGroupDomainNodes()[1], 2u);
+ }
}
}
diff --git a/ydb/core/mind/bscontroller/self_heal.cpp b/ydb/core/mind/bscontroller/self_heal.cpp
index 13bd7c56fb4..4dfee75874b 100644
--- a/ydb/core/mind/bscontroller/self_heal.cpp
+++ b/ydb/core/mind/bscontroller/self_heal.cpp
@@ -181,6 +181,7 @@ namespace NKikimr::NBsController {
auto *cmd = record.MutableReassignGroupDisk();
VDiskIDFromVDiskID(*VDiskToReplace, cmd->MutableVDiskId());
cmd->SetConvertToDonor(DonorMode);
+ cmd->SetAllowUnusableDisks(true);
cmd->SetIsSelfHealReasonDecommit(IsSelfHealReasonDecommit);
cmd->SetFromSelfHeal(true);
Send(MakeBlobStorageNodeWardenID(SelfId().NodeId()), ev.release());
diff --git a/ydb/core/protos/blobstorage_distributed_config.proto b/ydb/core/protos/blobstorage_distributed_config.proto
index e051fcb28b5..f0411a11f4d 100644
--- a/ydb/core/protos/blobstorage_distributed_config.proto
+++ b/ydb/core/protos/blobstorage_distributed_config.proto
@@ -198,6 +198,7 @@ message TEvNodeConfigInvokeOnRoot {
bool IgnoreVSlotQuotaCheck = 6;
bool IsSelfHealReasonDecommit = 7;
bool FromSelfHeal = 8;
+ bool AllowUnusableDisks = 9;
}
// Regenerate configuration so the slain VDisk is no more reported as DESTROY one in the list.