package org.ovirt.engine.core.bll;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.apache.commons.collections.comparators.ReverseComparator;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSGroup;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VdsSelectionAlgorithm;
import org.ovirt.engine.core.common.businessentities.VdsSpmStatus;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.utils.linq.DefaultMapper;
import org.ovirt.engine.core.utils.linq.LinqUtils;
import org.ovirt.engine.core.utils.linq.Predicate;
public class VdsCpuVdsLoadBalancingAlgorithm extends VdsLoadBalancingAlgorithm {
public VdsCpuVdsLoadBalancingAlgorithm(VDSGroup group) {
super(group);
}
@Override
protected void InitOverUtilizedList() {
// get vds that overcommited for the time defined
// LINQ FIX 29456
// OverUtilizedServers = AllRelevantVdss.
// Where(p => p.usage_cpu_percent >= p.high_utilization &&
// p.cpu_over_commit_time_stamp.HasValue &&
// ((TimeSpan)(DateTime.Now - p.cpu_over_commit_time_stamp.Value)).
// TotalMinutes >= p.cpu_over_commit_duration_minutes).
// OrderByDescending(p => p.usage_cpu_percent * p.cpu_cores /
// p.vds_strength).
// ToDictionary(i => i.vds_id);
List<VDS> relevantVdss = LinqUtils.filter(getAllRelevantVdss(), new Predicate<VDS>() {
@Override
public boolean eval(VDS p) {
return p.getusage_cpu_percent() >= p.gethigh_utilization()
&& p.getcpu_over_commit_time_stamp() != null
&& (new Date().getTime() - p.getcpu_over_commit_time_stamp().getTime()) >= p
.getcpu_over_commit_duration_minutes() * 1000 * 60;
}
});
Collections.sort(relevantVdss, createDescendingCpuComparator());
setOverUtilizedServers(LinqUtils.toMap(relevantVdss, new DefaultMapper<VDS, Guid>() {
@Override
public Guid createKey(VDS vds) {
return vds.getvds_id();
}
}));
log.infoFormat("VdsLoadBalancer: number of over utilized vdss found: {0}.", getOverUtilizedServers().size());
}
@SuppressWarnings("unchecked")
private Comparator<VDS> createDescendingCpuComparator() {
return new ReverseComparator(new VdsCpuUsageComparator());
}
@Override
protected void InitReadyToMigrationList() {
final int highVdsCount = Math
.min(Config.<Integer> GetValue(ConfigValues.UtilizationThresholdInPercent)
* getVdsGroup().gethigh_utilization() / 100,
getVdsGroup().gethigh_utilization()
- Config.<Integer> GetValue(ConfigValues.VcpuConsumptionPercentage));
// setReadyToMigrationServers(null); // LINQ AllRelevantVdss.Where(p =>
// (p.usage_cpu_percent + CalcSpmCpuConsumption(p)) < highVdsCount &&
// LINQ p.usage_cpu_percent > p.low_utilization).
// LINQ OrderBy(p => p.usage_cpu_percent * p.cpu_cores /
// p.vds_strength).
// LINQ ToDictionary(i => i.vds_id);
final boolean isEvenlyDistribute = VdsSelectionAlgorithm.EvenlyDistribute == getVdsGroup().getselection_algorithm();
List<VDS> relevantVdses = LinqUtils.filter(getAllRelevantVdss(), new Predicate<VDS>() {
@Override
public boolean eval(VDS p) {
return (p.getusage_cpu_percent() + CalcSpmCpuConsumption(p)) < highVdsCount
&& (isEvenlyDistribute || p.getusage_cpu_percent() > p.getlow_utilization());
}
});
Collections.sort(relevantVdses, new VdsCpuUsageComparator());
setReadyToMigrationServers(LinqUtils.toMap(relevantVdses, new DefaultMapper<VDS, Guid>() {
@Override
public Guid createKey(VDS i) {
return i.getvds_id();
}
}));
log.infoFormat("VdsLoadBalancer: max cpu limit: {0}, number of ready to migration vdss: {1}", highVdsCount,
getReadyToMigrationServers().size());
}
private int CalcSpmCpuConsumption(VDS vds) {
return ((vds.getspm_status() == VdsSpmStatus.None) ? 0 : Config
.<Integer> GetValue(ConfigValues.SpmVCpuConsumption)
* Config.<Integer> GetValue(ConfigValues.VcpuConsumptionPercentage) / vds.getcpu_cores());
}
@Override
protected void InitUnderUtilizedList() {
// get vds that undercommited for the time defined, order first by
// vm_count and then vds strength
// LINQ 29456
// UnderUtilizedServers = (from p in AllRelevantVdss
// where p.usage_cpu_percent < p.low_utilization &&
// p.cpu_over_commit_time_stamp.HasValue &&
// ((DateTime.Now - p.cpu_over_commit_time_stamp.Value)).
// TotalMinutes >= p.cpu_over_commit_duration_minutes
// orderby p.vm_count descending,
// (p.usage_cpu_percent * p.cpu_cores / p.vds_strength) descending
// select p).ToDictionary(i => i.vds_id);
if (VdsSelectionAlgorithm.EvenlyDistribute != getVdsGroup().getselection_algorithm()) {
List<VDS> vdses = LinqUtils.filter(getAllRelevantVdss(), new Predicate<VDS>() {
@Override
public boolean eval(VDS p) {
return p.getusage_cpu_percent() <= p.getlow_utilization()
&& p.getcpu_over_commit_time_stamp() != null
&& (new Date().getTime() - p.getcpu_over_commit_time_stamp().getTime()) >= p
.getcpu_over_commit_duration_minutes() * 60 * 1000;
}
});
// The order of sorting will be from smallest to biggest. The vm will be
// moved from less underutilized host to more underutilized host
Collections.sort(vdses, new Comparator<VDS>() {
@Override
public int compare(VDS o1, VDS o2) {
int primary = o1.getvm_count() - o2.getvm_count();
if (primary != 0)
return primary;
else {
return new VdsCpuUsageComparator().compare(o1, o2);
}
}
});
setUnderUtilizedServers(LinqUtils.toMap(vdses, new DefaultMapper<VDS, Guid>() {
@Override
public Guid createKey(VDS vds) {
return vds.getvds_id();
}
}));
log.infoFormat("VdsLoadBalancer: number of under utilized hosts found: {0}.",
getUnderUtilizedServers().size());
} else {
setUnderUtilizedServers(Collections.EMPTY_MAP);
}
}
@Override
protected VM getBestVmToMigrate(List<VM> vms, final Guid vdsId) {
// get the vm with the min cpu usage that its not his dedicated vds
List<VM> vms1 = LinqUtils.filter(vms, new Predicate<VM>() {
@Override
public boolean eval(VM v) {
return !vdsId.equals(v.getdedicated_vm_for_vds());
}
});
VM result = null;
if (!vms1.isEmpty()) {
result = Collections.min(vms1, new VmCpuUsageComparator());
}
// if no vm found return the vm with min cpu
if (result == null) {
log.info("VdsLoadBalancer: vm selection - no vm without pending found.");
result = Collections.min(vms, new VmCpuUsageComparator());
}
log.infoFormat("VdsLoadBalancer: vm selection - selected vm: {0}, cpu: {1}.", result.getvm_name(),
result.getusage_cpu_percent());
return result;
}
private static LogCompat log = LogFactoryCompat.getLog(VdsCpuVdsLoadBalancingAlgorithm.class);
/**
* Comparator that compares the CPU usage of two hosts, with regard to the number of CPUs each host has and it's
* strength.
*/
private final class VdsCpuUsageComparator implements Comparator<VDS> {
@Override
public int compare(VDS o1, VDS o2) {
return Integer.valueOf(calculateCpuUsage(o1)).compareTo(calculateCpuUsage(o2));
}
private int calculateCpuUsage(VDS o1) {
return o1.getusage_cpu_percent() * o1.getcpu_cores() / o1.getvds_strength();
}
}
/**
* Comparator that compares the CPU usage of two VMs, with regard to the number of CPUs each VM has.
*/
private final class VmCpuUsageComparator implements Comparator<VM> {
@Override
public int compare(VM o1, VM o2) {
return Integer.valueOf(calculateCpuUsage(o1)).compareTo(calculateCpuUsage(o2));
}
private int calculateCpuUsage(VM o1) {
return o1.getusage_cpu_percent() * o1.getnum_of_cpus();
}
}
}