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);
    }
}