From 3aa0e9a352a83a2bea18a9754d0c2fd6a4112b0c Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Fri, 10 Aug 2012 16:15:25 +0530 Subject: [PATCH] bug CS-15278: For removing clusters crossing threshold find out the list of cluster through db instead of iteratting cluster one by one in the java code. Reviewed-by: Koushik --- .../com/cloud/deploy/DeploymentPlanner.java | 8 +++ .../com/cloud/capacity/dao/CapacityDao.java | 3 +- .../cloud/capacity/dao/CapacityDaoImpl.java | 54 +++++++++++++++- .../src/com/cloud/deploy/FirstFitPlanner.java | 63 +++++++++---------- 4 files changed, 93 insertions(+), 35 deletions(-) diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index b511a790f10..853b41c5386 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -12,6 +12,7 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.deploy; +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -176,6 +177,13 @@ public interface DeploymentPlanner extends Adapter { _clusterIds.add(clusterId); } + public void addClusterList(Collection clusterList) { + if (_clusterIds == null) { + _clusterIds = new HashSet(); + } + _clusterIds.addAll(clusterList); + } + public void addHost(long hostId) { if (_hostIds == null) { _hostIds = new HashSet(); diff --git a/server/src/com/cloud/capacity/dao/CapacityDao.java b/server/src/com/cloud/capacity/dao/CapacityDao.java index 0906952b8e0..4ac967035d3 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDao.java +++ b/server/src/com/cloud/capacity/dao/CapacityDao.java @@ -36,5 +36,6 @@ public interface CapacityDao extends GenericDao { Long podId, Long clusterId, String resourceState); List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); void updateCapacityState(Long dcId, Long podId, Long clusterId, - Long hostId, String capacityState); + Long hostId, String capacityState); + List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long computeRequested, Float overProvFactor); } diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java index 86da5ef4732..94ef67c6631 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -30,6 +30,7 @@ import com.cloud.storage.Storage; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.dao.StoragePoolDaoImpl; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -104,7 +105,12 @@ public class CapacityDaoImpl extends GenericDaoBase implements "WHERE total_capacity > 0 AND cluster_id is not null AND capacity_state='Enabled'"; private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART2 = " GROUP BY cluster_id, capacity_type order by percent desc limit "; private static final String UPDATE_CAPACITY_STATE = "UPDATE `cloud`.`op_host_capacity` SET capacity_state = ? WHERE "; - + private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT cluster_id " + + "FROM (SELECT cluster_id, ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(total_capacity) ) ratio "+ + "FROM `cloud`.`op_host_capacity` capacity "+ + "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 "+ + "GROUP BY cluster_id) tmp " + + "WHERE tmp.ratio > ? "; public CapacityDaoImpl() { @@ -128,6 +134,52 @@ public class CapacityDaoImpl extends GenericDaoBase implements _allFieldsSearch.done(); } + + @Override + public List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long compute_requested, Float overProvFactor){ + + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + List result = new ArrayList(); + StringBuilder sql = new StringBuilder(LIST_CLUSTERS_CROSSING_THRESHOLD); + + + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + pstmt.setLong(1, compute_requested); + pstmt.setLong(2, zoneId); + pstmt.setShort(3, capacityType); + pstmt.setFloat(4, disableThreshold*overProvFactor); + + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + result.add(rs.getLong(1)); + } + return result; + } catch (SQLException e) { + throw new CloudRuntimeException("DB Exception on: " + sql, e); + } catch (Throwable e) { + throw new CloudRuntimeException("Caught: " + sql, e); + } + } + + /*public static String preparePlaceHolders(int length) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length;) { + builder.append("?"); + if (++i < length) { + builder.append(","); + } + } + return builder.toString(); + } + + public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException { + for (int i = 0; i < values.length; i++) { + preparedStatement.setObject(i + 1, values[i]); + } + }*/ + @Override public List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, String resource_state){ diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 77c1007421d..8133f4be763 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -66,6 +66,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.user.AccountManager; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.component.Adapters; import com.cloud.utils.component.Inject; import com.cloud.vm.DiskProfile; @@ -447,7 +448,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return capacityList; } - private void removeClustersCrossingThreshold(List clusterList, ExcludeList avoid, VirtualMachineProfile vmProfile){ + private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan){ Map capacityThresholdMap = getCapacityThresholdMap(); List capacityList = getCapacitiesForCheckingThreshold(); @@ -457,37 +458,33 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; - // Iterate over the cluster List and check for each cluster whether it breaks disable threshold for any of the capacity types - for (Long clusterId : clusterList){ - for(short capacity : capacityList){ - - List summedCapacityList = _capacityDao.findCapacityBy(new Integer(capacity), null, null, clusterId); - if (summedCapacityList != null && summedCapacityList.size() != 0 && summedCapacityList.get(0).getTotalCapacity() != 0){ - - double used = (double)(summedCapacityList.get(0).getUsedCapacity() + summedCapacityList.get(0).getReservedCapacity()); - double total = summedCapacityList.get(0).getTotalCapacity(); - - if (capacity == Capacity.CAPACITY_TYPE_CPU){ - total = total * ApiDBUtils.getCpuOverprovisioningFactor(); - used = used + cpu_requested; - }else{ - used = used + ram_requested; - } - - double usedPercentage = used/total; - if ( usedPercentage > capacityThresholdMap.get(capacity)){ - avoid.addCluster(clusterId); - clustersCrossingThreshold.add(clusterId); - s_logger.debug("Cannot allocate cluster " + clusterId + " for vm creation since its allocated percentage: " +usedPercentage + - " will cross the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping this cluster"); - break; - } - } - } - } - - clusterList.removeAll(clustersCrossingThreshold); - + // For each capacity get the cluster list crossing the threshold and remove it from the clusterList that will be used for vm allocation. + for(short capacity : capacityList){ + + if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0){ + return; + } + + if (capacity == Capacity.CAPACITY_TYPE_CPU){ + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(Capacity.CAPACITY_TYPE_CPU, plan.getDataCenterId(), + capacityThresholdMap.get(capacity), cpu_requested, ApiDBUtils.getCpuOverprovisioningFactor()); + }else{ + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), + capacityThresholdMap.get(capacity), ram_requested, 1.0f);//Mem overprov not supported yet + } + + + if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0){ + // addToAvoid Set + avoid.addClusterList(clustersCrossingThreshold); + // Remove clusters crossing disabled threshold + clusterListForVmAllocation.removeAll(clustersCrossingThreshold); + + s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + + " crosses the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping these clusters"); + } + + } } private DeployDestination checkClustersforDestination(List clusterList, VirtualMachineProfile vmProfile, @@ -497,7 +494,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { s_logger.trace("ClusterId List to consider: " + clusterList); } - removeClustersCrossingThreshold(clusterList, avoid, vmProfile); + removeClustersCrossingThreshold(clusterList, avoid, vmProfile, plan); for(Long clusterId : clusterList){ Cluster clusterVO = _clusterDao.findById(clusterId);