package org.ovirt.engine.core.bll.scheduling.policyunits; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.lang.math.NumberUtils; import org.ovirt.engine.core.bll.scheduling.PolicyUnitImpl; import org.ovirt.engine.core.bll.scheduling.PolicyUnitParameter; import org.ovirt.engine.core.bll.scheduling.SchedulingUnit; import org.ovirt.engine.core.bll.scheduling.pending.PendingResourceManager; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.scheduling.PerHostMessages; import org.ovirt.engine.core.common.scheduling.PolicyUnit; import org.ovirt.engine.core.common.scheduling.PolicyUnitType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SchedulingUnit( guid = "43b9e654-337f-4b0d-a896-cbb22ce5a7fc", name = "Swap", description = "Filters out hosts that are swapping", type = PolicyUnitType.FILTER, parameters = { PolicyUnitParameter.MAX_ALLOWED_SWAP_USAGE } ) public class SwapFilterPolicyUnit extends PolicyUnitImpl { private static final Logger log = LoggerFactory.getLogger(SwapFilterPolicyUnit.class); public SwapFilterPolicyUnit(PolicyUnit policyUnit, PendingResourceManager pendingResourceManager) { super(policyUnit, pendingResourceManager); } @Override public List<VDS> filter(Cluster cluster, List<VDS> hosts, VM vm, Map<String, String> parameters, PerHostMessages messages) { if (!Config.<Boolean> getValue(ConfigValues.EnableSwapCheck)) { return hosts; // Ignore swap usage } // If VM in Paused mode - no additional memory allocation needed if (vm.getStatus() == VMStatus.Paused) { return hosts; } List<VDS> goodHosts = new ArrayList<>(); final int allowedSwapUsage = NumberUtils.toInt(parameters.get(PolicyUnitParameter.MAX_ALLOWED_SWAP_USAGE.getDbName()), Config.<Integer>getValue(ConfigValues.BlockMigrationOnSwapUsagePercentage)); for (VDS vds : hosts) { if (isHostSwapping(vds, allowedSwapUsage)) { log.debug("Host '{}' is swapping more than allowed. Ignoring it.", vds.getName()); messages.addMessage(vds.getId(), EngineMessage.VAR__DETAIL__SWAP_VALUE_ILLEGAL.toString()); continue; } goodHosts.add(vds); } return goodHosts; } /** * Determines whether a host is swapping more than the defined threshold. * * @param host The host. * @param allowedSwapUsage The allowed percentage of swap before we consider * the host to be swapping * @return true if the host is swapping; otherwise false. */ private boolean isHostSwapping(VDS host, int allowedSwapUsage) { if (host.getSwapTotal() == null || host.getSwapFree() == null || host.getMemFree() == null || host.getMemFree() <= 0 || host.getPhysicalMemMb() == null || host.getPhysicalMemMb() <= 0) { return false; // No swap information available } long swapTotal = host.getSwapTotal(); long swapFree = host.getSwapFree(); long memFree = host.getMemFree(); long physicalMemMb = host.getPhysicalMemMb(); // Compute how much swap is used (taking into consideration available // RAM) as a percentage from physical memory return ((swapTotal - swapFree - memFree) * 100 / physicalMemMb) > allowedSwapUsage; } }