diff --git a/server/src/com/cloud/capacity/dao/CapacityDao.java b/server/src/com/cloud/capacity/dao/CapacityDao.java index fb0b42db194..988356b7d92 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDao.java +++ b/server/src/com/cloud/capacity/dao/CapacityDao.java @@ -21,16 +21,16 @@ package com.cloud.capacity.dao; import java.util.List; import com.cloud.capacity.CapacityVO; -import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity; import com.cloud.utils.db.GenericDao; public interface CapacityDao extends GenericDao { CapacityVO findByHostIdType(Long hostId, short capacityType); - List orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor); + List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor); List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType, float cpuOverprovisioningFactor); List findCapacityByType(short capacityType, Long zoneId, Long podId, Long clusterId, Long startIndex, Long pageSize); boolean removeBy(Short capacityType, Long zoneId, Long podId, Long clusterId); List findByClusterPodZone(Long zoneId, Long podId, Long clusterId); List findNonSharedStorageForClusterPodZone(Long zoneId,Long podId, Long clusterId); + List orderClustersByAggregateCapacity(long id, short capacityType, boolean isZone, float cpuOverprovisioningFactor); } diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java index 78420fd5b2a..41b13504f90 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -30,20 +30,16 @@ import org.apache.log4j.Logger; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; -import com.cloud.host.dao.HostDaoImpl; import com.cloud.storage.Storage; import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolDaoImpl; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; -import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; @@ -59,18 +55,22 @@ public class CapacityDaoImpl extends GenericDaoBase implements private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1 = "SELECT DISTINCT capacity.cluster_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster on (cluster.id = capacity.cluster_id AND cluster.removed is NULL) WHERE "; private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ? " + "AND cluster_id IN (SELECT distinct cluster_id FROM `cloud`.`op_host_capacity` WHERE "; - private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) " + - "ORDER BY ((total_capacity * ?) - used_capacity + reserved_capacity) DESC"; + private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) "; - private SearchBuilder _hostIdTypeSearch; - private SearchBuilder _hostOrPoolIdSearch; + private final SearchBuilder _hostIdTypeSearch; + private final SearchBuilder _hostOrPoolIdSearch; protected GenericSearchBuilder SummedCapacitySearch; private SearchBuilder _allFieldsSearch; protected final StoragePoolDaoImpl _storagePoolDao = ComponentLocator.inject(StoragePoolDaoImpl.class); + - private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = "SELECT a.host_id FROM (host JOIN op_host_capacity a ON host.id = a.host_id AND host.cluster_id = ? AND host.type = ? " + + private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = "SELECT a.host_id FROM (host JOIN op_host_capacity a ON host.id = a.host_id AND host.cluster_id = ? AND host.type = ? " + "AND (a.total_capacity * ? - a.used_capacity) >= ? and a.capacity_type = 1) " + "JOIN op_host_capacity b ON a.host_id = b.host_id AND b.total_capacity - b.used_capacity >= ? AND b.capacity_type = 0"; + + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1 = "SELECT cluster_id FROM `cloud`.`op_host_capacity` WHERE " ; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2 = " AND capacity_type = ? GROUP BY cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) ASC"; + public CapacityDaoImpl() { _hostIdTypeSearch = createSearchBuilder(); @@ -164,7 +164,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public List orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){ + public List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){ Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -187,27 +187,15 @@ public class CapacityDaoImpl extends GenericDaoBase implements try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, id); - if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){ - pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU); - pstmt.setFloat(3, cpuOverprovisioningFactor); - pstmt.setLong(4, requiredCpu); - pstmt.setLong(5, id); - pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY); - pstmt.setFloat(7, 1); - pstmt.setLong(8, requiredRam); - pstmt.setFloat(9, cpuOverprovisioningFactor); - }else{ - pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_MEMORY); - pstmt.setFloat(3, 1); - pstmt.setLong(4, requiredRam); - pstmt.setLong(5, id); - pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_CPU); - pstmt.setFloat(7, cpuOverprovisioningFactor); - pstmt.setLong(8, requiredCpu); - pstmt.setFloat(9, 1); - } - - ResultSet rs = pstmt.executeQuery(); + pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU); + pstmt.setFloat(3, cpuOverprovisioningFactor); + pstmt.setLong(4, requiredCpu); + pstmt.setLong(5, id); + pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY); + pstmt.setFloat(7, 1); + pstmt.setLong(8, requiredRam); + + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { result.add(rs.getLong(1)); } @@ -363,4 +351,41 @@ public class CapacityDaoImpl extends GenericDaoBase implements return remove(sc) > 0; } + + @Override + public List orderClustersByAggregateCapacity(long id, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){ + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + List result = new ArrayList(); + + StringBuilder sql = new StringBuilder(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1); + + if(isZone){ + sql.append("data_center_id = ?"); + }else{ + sql.append("pod_id = ?"); + } + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2); + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + pstmt.setLong(1, id); + pstmt.setShort(2, capacityTypeForOrdering); + + if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){ + pstmt.setFloat(3, cpuOverprovisioningFactor); + }else{ + pstmt.setFloat(3, 1); + } + + 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); + } + } } diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 40e9f8c10c8..bd302c05196 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -458,9 +458,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { //look at the aggregate available cpu and ram per cluster //although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot - //we need clusters having enough cpu AND RAM + //we need clusters having enough cpu AND RAM to host this particular VM and order them by aggregate cluster capacity if (s_logger.isDebugEnabled()) { - s_logger.debug("Listing clusters that have enough aggregate CPU and RAM capacity under this "+(isZone ? "Zone: " : "Pod: " )+id); + s_logger.debug("Listing clusters in order of aggregate capacity, that have (atleast one host with) enough CPU and RAM capacity under this "+(isZone ? "Zone: " : "Pod: " )+id); } String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key()); short capacityType = CapacityVO.CAPACITY_TYPE_CPU; @@ -471,11 +471,22 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { if (s_logger.isDebugEnabled()) { s_logger.debug("CPUOverprovisioningFactor considered: " + cpuOverprovisioningFactor); } - List clusterIdswithEnoughCapacity = _capacityDao.orderClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone, cpuOverprovisioningFactor); + List clusterIdswithEnoughCapacity = _capacityDao.listClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone, cpuOverprovisioningFactor); if (s_logger.isTraceEnabled()) { - s_logger.trace("ClusterId List having enough aggregate capacity: " + clusterIdswithEnoughCapacity); + s_logger.trace("ClusterId List having enough CPU and RAM capacity: " + clusterIdswithEnoughCapacity); } - return clusterIdswithEnoughCapacity; + List clusterIdsOrderedByAggregateCapacity = _capacityDao.orderClustersByAggregateCapacity(id, capacityType, isZone, cpuOverprovisioningFactor); + //only keep the clusters that have enough capacity to host this VM + if (s_logger.isTraceEnabled()) { + s_logger.trace("ClusterId List in order of aggregate capacity: " + clusterIdsOrderedByAggregateCapacity); + } + clusterIdsOrderedByAggregateCapacity.retainAll(clusterIdswithEnoughCapacity); + + if (s_logger.isTraceEnabled()) { + s_logger.trace("ClusterId List having enough CPU and RAM capacity & in order of aggregate capacity: " + clusterIdsOrderedByAggregateCapacity); + } + + return clusterIdsOrderedByAggregateCapacity; }