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