package org.zstack.compute.allocator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.compute.host.HostGlobalConfig; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.header.allocator.HostAllocatorConstant; import org.zstack.header.allocator.HostCpuOverProvisioningManager; import org.zstack.header.host.RecalculateHostCapacityMsg; import org.zstack.header.zone.ZoneVO; import org.zstack.header.zone.ZoneVO_; import org.zstack.utils.CollectionUtils; import org.zstack.utils.function.Function; import javax.persistence.Query; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Created by xing5 on 2016/5/12. */ public class HostCpuOverProvisioningManagerImpl implements HostCpuOverProvisioningManager { private Integer globalRatio; private ConcurrentHashMap<String, Integer> ratios = new ConcurrentHashMap<String, Integer>(); @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; @Override public void setGlobalRatio(int ratio) { globalRatio = ratio; updateHostsCpuCapacity(ratio); recalculateAllHostCapacity(); } private void recalculateAllHostCapacity() { SimpleQuery<ZoneVO> q = dbf.createQuery(ZoneVO.class); q.select(ZoneVO_.uuid); List<String> zuuids = q.listValue(); if (zuuids.isEmpty()) { return; } List<RecalculateHostCapacityMsg> rmsgs = CollectionUtils.transformToList(zuuids, new Function<RecalculateHostCapacityMsg, String>() { @Override public RecalculateHostCapacityMsg call(String arg) { RecalculateHostCapacityMsg msg = new RecalculateHostCapacityMsg(); msg.setZoneUuid(arg); bus.makeLocalServiceId(msg, HostAllocatorConstant.SERVICE_ID); return msg; } }); bus.send(rmsgs); } @Transactional private void updateHostsCpuCapacity(int ratio) { if (ratios.isEmpty()) { // all hosts use global ratio String sql = String.format("update HostCapacityVO cap set cap.totalCpu = cap.cpuNum * %s", ratio); Query q = dbf.getEntityManager().createQuery(sql); q.executeUpdate(); } else { // part of hosts use global ratio String sql = String.format("update HostCapacityVO cap set cap.totalCpu = cap.cpuNum * %s where cap.uuid not in (:uuids)", ratio); Query q = dbf.getEntityManager().createQuery(sql); q.setParameter("uuids", ratios.keySet()); q.executeUpdate(); } } @Override public int getGlobalRatio() { return globalRatio == null ? HostGlobalConfig.HOST_CPU_OVER_PROVISIONING_RATIO.value(Integer.class) : globalRatio; } @Override public void setRatio(String hostUuid, int ratio) { ratios.put(hostUuid, ratio); updateHostCpuCapacityByUuid(hostUuid, ratio); recalculateHostCapacityByUuid(hostUuid); } @Transactional private void updateHostCpuCapacityByUuid(String hostUuid, int ratio) { String sql = String.format("update HostCapacityVO cap set cap.totalCpu = cap.cpuNum * %s where cap.uuid = :huuid", ratio); Query q = dbf.getEntityManager().createQuery(sql); q.setParameter("huuid", hostUuid); q.executeUpdate(); } @Override public void deleteRatio(String hostUuid) { ratios.remove(hostUuid); updateHostCpuCapacityByUuid(hostUuid, getGlobalRatio()); recalculateHostCapacityByUuid(hostUuid); } private void recalculateHostCapacityByUuid(String hostUuid) { RecalculateHostCapacityMsg msg = new RecalculateHostCapacityMsg(); msg.setHostUuid(hostUuid); bus.makeLocalServiceId(msg, HostAllocatorConstant.SERVICE_ID); bus.send(msg); } @Override public int getRatio(String hostUuid) { Integer r = ratios.get(hostUuid); return r == null ? getGlobalRatio() : r; } @Override public Map<String, Integer> getAllRatio() { return ratios; } @Override public int calculateByRatio(String hostUuid, int cpuNum) { int r = getRatio(hostUuid); int ret = Math.round(cpuNum / r); return ret == 0 ? 1 : ret; } @Override public int calculateHostCpuByRatio(String hostUuid, int cpuNum) { int r = getRatio(hostUuid); return cpuNum * r; } }