void PreferredLocationConstraint::GetTargetNodes( TempSolution const& tempSolution, PlacementReplica const* replica, NodeSet & candidateNodes, NodeToConstraintDiagnosticsDataMapSPtr const nodeToConstraintDiagnosticsDataMapSPtr) const { UNREFERENCED_PARAMETER(nodeToConstraintDiagnosticsDataMapSPtr); PartitionEntry const* partition = replica->Partition; if (partition->Service->OnEveryNode) { return; } bool hasPreferredLocations = partition->ExistsUpgradeLocation || !partition->StandByLocations.empty(); set<Common::TreeNodeIndex> const& upgradedUDs = PreferredLocationConstraint::GetUpgradedUDs(tempSolution, partition); bool hasUpgradCompletedUDs = !upgradedUDs.empty(); if (replica->IsNew && !hasPreferredLocations && !hasUpgradCompletedUDs) { return; } // Use prefer locations if exist, otherwise, use completed UDs NodeSet nodesUpgradedUDs(candidateNodes); if (!hasPreferredLocations && hasUpgradCompletedUDs) { // Only prefer upgraded nodes if SB/Upgrade location is empty nodesUpgradedUDs.Filter([&](NodeEntry const *node) -> bool { return CheckUpgradedUDs(upgradedUDs, node); }); } candidateNodes.Intersect([=](function<void(NodeEntry const *)> f) { // During singleton replica upgrade, there could be replicas which are not in upgrade, // but are correlated to the ones that are in upgrade (affinity or scaleout), // and need to be moved together with replicas which are in upgrade if ((partition->IsInUpgrade || partition->IsInSingletonReplicaUpgradeOptimization()) && partition->ExistsUpgradeLocation) { if (partition->PrimaryUpgradeLocation) { f(partition->PrimaryUpgradeLocation); } else { for (auto it = partition->SecondaryUpgradeLocations.begin(); it != partition->SecondaryUpgradeLocations.end(); ++it) { f(*it); } } } for (auto itNode = partition->StandByLocations.begin(); itNode != partition->StandByLocations.end(); ++itNode) { f(*itNode); } partition->ForEachExistingReplica([&f](PlacementReplica const* r) { f(r->Node); }, true, false); }); if (!hasPreferredLocations && hasUpgradCompletedUDs) { candidateNodes.Union(nodesUpgradedUDs); } }
void PreferredLocationSubspace::GetNodesForReplicaDrop( TempSolution const& tempSolution, PartitionEntry const& partition, NodeSet & candidateNodes) const { // Number of elements in these vectors will be at most equal to number of replicas. // In general case, that is orders of magnitude smaller than number of nodes in the cluster. // Using std::vector, NodeSet::Intersect will have smaller complexity than if we used NodeSet here. std::vector<NodeEntry const*> blocklistedAndMoveInProgressNodes; std::vector<NodeEntry const*> moveInProgressReplicasNodes; std::vector<NodeEntry const*> blocklistedNodesWithReplicas; std::vector<NodeEntry const*> fdNodesWithMoreThanQuorumReplicas; std::vector<NodeEntry const*> udNodesWithMoreThanQuorumReplicas; ServiceEntry const* service = partition.Service; // Active replicas marked with MoveInProgress should be prioritized for dropping partition.ForEachExistingReplica([&](PlacementReplica const* r) { NodeEntry const* node = tempSolution.GetReplicaLocation(r); if (nullptr == node) { return; } if (r->IsMoveInProgress && service->IsNodeInBlockList(node)) { blocklistedAndMoveInProgressNodes.push_back(node); } else if (r->IsMoveInProgress) { moveInProgressReplicasNodes.push_back(node); } else if (service->IsNodeInBlockList(node)) { blocklistedNodesWithReplicas.push_back(node); } else if (!service->OnEveryNode) { auto& settings = tempSolution.OriginalPlacement->Settings; if (settings.FaultDomainEnabled && settings.FaultDomainConstraintPriority != -1 && settings.QuorumBasedReplicaDistributionPerFaultDomains && service->FDDistribution != Service::Type::Ignore && !tempSolution.OriginalPlacement->BalanceCheckerObj->FaultDomainStructure.IsEmpty) { if (IsNodeInOverloadedDomain(tempSolution, r->Partition, node, true)) { fdNodesWithMoreThanQuorumReplicas.push_back(node); } } if (settings.UpgradeDomainEnabled && settings.UpgradeDomainConstraintPriority != -1 && settings.QuorumBasedReplicaDistributionPerUpgradeDomains && !tempSolution.OriginalPlacement->BalanceCheckerObj->UpgradeDomainStructure.IsEmpty) { if (IsNodeInOverloadedDomain(tempSolution, r->Partition, node, false)) { udNodesWithMoreThanQuorumReplicas.push_back(node); } } } }, false, true); if (!blocklistedAndMoveInProgressNodes.empty()) { candidateNodes.Intersect([&](function<void(NodeEntry const *)> f) { for (auto itNode = blocklistedAndMoveInProgressNodes.begin(); itNode != blocklistedAndMoveInProgressNodes.end(); ++itNode) { f(*itNode); } }); } else if (!moveInProgressReplicasNodes.empty()) { candidateNodes.Intersect([&](function<void(NodeEntry const *)> f) { for (auto itNode = moveInProgressReplicasNodes.begin(); itNode != moveInProgressReplicasNodes.end(); ++itNode) { f(*itNode); } }); } else if (!blocklistedNodesWithReplicas.empty()) { candidateNodes.Intersect([&](function<void(NodeEntry const *)> f) { for (auto itNode = blocklistedNodesWithReplicas.begin(); itNode != blocklistedNodesWithReplicas.end(); ++itNode) { f(*itNode); } }); } else if (!udNodesWithMoreThanQuorumReplicas.empty()) { candidateNodes.Intersect([&](function<void(NodeEntry const *)> f) { for (auto itNode = udNodesWithMoreThanQuorumReplicas.begin(); itNode != udNodesWithMoreThanQuorumReplicas.end(); ++itNode) { f(*itNode); } }); } else if (!fdNodesWithMoreThanQuorumReplicas.empty()) { candidateNodes.Intersect([&](function<void(NodeEntry const *)> f) { for (auto itNode = fdNodesWithMoreThanQuorumReplicas.begin(); itNode != fdNodesWithMoreThanQuorumReplicas.end(); ++itNode) { f(*itNode); } }); } }