DaanHoogland commented on code in PR #12014:
URL: https://github.com/apache/cloudstack/pull/12014#discussion_r2509206232


##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -357,10 +372,90 @@ List<Ternary<VirtualMachine, Host, Host>> 
getDrsPlan(Cluster cluster,
                     serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), 
vm.getServiceOfferingId()));
         }
 
+        // PHASE 1: Pre-compute suitable hosts (once per eligible VM - never 
changes)
+        // Use listHostsForMigrationOfVM to get hosts validated by 
getCapableSuitableHosts
+        // This ensures DRS uses the same validation as "find host for 
migration" command

Review Comment:
   new method with this as javadoc;
   ```suggestion
       /*
        * PHASE 1: Pre-compute suitable hosts (once per eligible VM - never 
changes)
        *   Use listHostsForMigrationOfVM to get hosts validated by 
getCapableSuitableHosts
        *   This ensures DRS uses the same validation as "find host for 
migration” command
        */
   ```



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -438,32 +537,104 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster 
cluster, ClusterDrsAlgorithm
             List<VirtualMachine> vmList,
             Map<Long, ServiceOffering> vmIdServiceOfferingMap,
             Map<Long, Ternary<Long, Long, Long>> hostCpuCapacityMap,
-            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap) throws 
ConfigurationException {
+            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap,
+            Map<Long, List<? extends Host>> vmToCompatibleHostsCache,
+            Map<Long, Map<Host, Boolean>> vmToStorageMotionCache,
+            Map<Long, ExcludeList> vmToExcludesMap) throws 
ConfigurationException {
+        // Pre-calculate cluster imbalance once per iteration (same for all 
VM-host combinations)
+        Double preImbalance = getClusterImbalance(cluster.getId(),
+                new ArrayList<>(hostCpuCapacityMap.values()),
+                new ArrayList<>(hostMemoryCapacityMap.values()),
+                null);
+
+        // Pre-calculate base metrics array once per iteration for optimized 
imbalance calculation
+        // This reduces complexity from O(V × H × H) to O(V × H) per iteration
+        String metricType = getClusterDrsMetric(cluster.getId());
+        Map<Long, Ternary<Long, Long, Long>> baseMetricsMap = 
"cpu".equals(metricType) ? hostCpuCapacityMap : hostMemoryCapacityMap;
+        double[] baseMetricsArray = new double[baseMetricsMap.size()];
+        Map<Long, Integer> hostIdToIndexMap = new HashMap<>();
+
+        int index = 0;
+        for (Map.Entry<Long, Ternary<Long, Long, Long>> entry : 
baseMetricsMap.entrySet()) {
+            Long hostId = entry.getKey();
+            Ternary<Long, Long, Long> metrics = entry.getValue();
+            long used = metrics.first();
+            long actualTotal = metrics.third() - metrics.second();
+            long free = actualTotal - metrics.first();
+            Double metricValue = getMetricValue(cluster.getId(), used, free, 
actualTotal, null);
+            if (metricValue != null) {
+                baseMetricsArray[index] = metricValue;
+                hostIdToIndexMap.put(hostId, index);
+                index++;
+            }
+        }
+
+        // Trim array if some values were null
+        if (index < baseMetricsArray.length) {
+            double[] trimmed = new double[index];
+            System.arraycopy(baseMetricsArray, 0, trimmed, 0, index);
+            baseMetricsArray = trimmed;
+        }
+
         double improvement = 0;
         Pair<VirtualMachine, Host> bestMigration = new Pair<>(null, null);
 
         for (VirtualMachine vm : vmList) {
             if (vm.getType().isUsedBySystem() || vm.getState() != 
VirtualMachine.State.Running ||
                     (MapUtils.isNotEmpty(vm.getDetails()) &&
-                            
vm.getDetails().get(VmDetailConstants.SKIP_DRS).equalsIgnoreCase("true"))
+                            
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))
             ) {
                 continue;
             }
-            Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, 
Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
-                    .listHostsForMigrationOfVM(
-                            vm, 0L, 500L, null, vmList);
-            List<? extends Host> compatibleDestinationHosts = 
hostsForMigrationOfVM.first().first();
-            List<? extends Host> suitableDestinationHosts = 
hostsForMigrationOfVM.second();
 
-            Map<Host, Boolean> requiresStorageMotion = 
hostsForMigrationOfVM.third();
+            // Use cached compatible hosts
+            List<? extends Host> compatibleHosts = 
vmToCompatibleHostsCache.get(vm.getId());
+            Map<Host, Boolean> requiresStorageMotion = 
vmToStorageMotionCache.get(vm.getId());
+            ExcludeList excludes = vmToExcludesMap.get(vm.getId());
+
+            if (CollectionUtils.isEmpty(compatibleHosts)) {
+                continue;
+            }
+
+            ServiceOffering serviceOffering = 
vmIdServiceOfferingMap.get(vm.getId());
+            if (serviceOffering == null) {
+                continue;
+            }
 
-            for (Host destHost : compatibleDestinationHosts) {
-                if (!suitableDestinationHosts.contains(destHost) || 
cluster.getId() != destHost.getClusterId()) {
+            // Pre-calculate VM resource requirements for quick capacity 
filtering

Review Comment:
   `PreCalculateVMsResourceRequirementsForQuickCapacityFiltering()`



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -438,32 +537,104 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster 
cluster, ClusterDrsAlgorithm
             List<VirtualMachine> vmList,
             Map<Long, ServiceOffering> vmIdServiceOfferingMap,
             Map<Long, Ternary<Long, Long, Long>> hostCpuCapacityMap,
-            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap) throws 
ConfigurationException {
+            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap,
+            Map<Long, List<? extends Host>> vmToCompatibleHostsCache,
+            Map<Long, Map<Host, Boolean>> vmToStorageMotionCache,
+            Map<Long, ExcludeList> vmToExcludesMap) throws 
ConfigurationException {
+        // Pre-calculate cluster imbalance once per iteration (same for all 
VM-host combinations)
+        Double preImbalance = getClusterImbalance(cluster.getId(),
+                new ArrayList<>(hostCpuCapacityMap.values()),
+                new ArrayList<>(hostMemoryCapacityMap.values()),
+                null);
+
+        // Pre-calculate base metrics array once per iteration for optimized 
imbalance calculation
+        // This reduces complexity from O(V × H × H) to O(V × H) per iteration
+        String metricType = getClusterDrsMetric(cluster.getId());
+        Map<Long, Ternary<Long, Long, Long>> baseMetricsMap = 
"cpu".equals(metricType) ? hostCpuCapacityMap : hostMemoryCapacityMap;
+        double[] baseMetricsArray = new double[baseMetricsMap.size()];
+        Map<Long, Integer> hostIdToIndexMap = new HashMap<>();
+
+        int index = 0;
+        for (Map.Entry<Long, Ternary<Long, Long, Long>> entry : 
baseMetricsMap.entrySet()) {
+            Long hostId = entry.getKey();
+            Ternary<Long, Long, Long> metrics = entry.getValue();
+            long used = metrics.first();
+            long actualTotal = metrics.third() - metrics.second();
+            long free = actualTotal - metrics.first();
+            Double metricValue = getMetricValue(cluster.getId(), used, free, 
actualTotal, null);
+            if (metricValue != null) {
+                baseMetricsArray[index] = metricValue;
+                hostIdToIndexMap.put(hostId, index);
+                index++;
+            }
+        }
+
+        // Trim array if some values were null
+        if (index < baseMetricsArray.length) {
+            double[] trimmed = new double[index];
+            System.arraycopy(baseMetricsArray, 0, trimmed, 0, index);
+            baseMetricsArray = trimmed;
+        }
+
         double improvement = 0;
         Pair<VirtualMachine, Host> bestMigration = new Pair<>(null, null);
 
         for (VirtualMachine vm : vmList) {
             if (vm.getType().isUsedBySystem() || vm.getState() != 
VirtualMachine.State.Running ||
                     (MapUtils.isNotEmpty(vm.getDetails()) &&
-                            
vm.getDetails().get(VmDetailConstants.SKIP_DRS).equalsIgnoreCase("true"))
+                            
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))
             ) {
                 continue;
             }
-            Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, 
Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
-                    .listHostsForMigrationOfVM(
-                            vm, 0L, 500L, null, vmList);
-            List<? extends Host> compatibleDestinationHosts = 
hostsForMigrationOfVM.first().first();
-            List<? extends Host> suitableDestinationHosts = 
hostsForMigrationOfVM.second();
 
-            Map<Host, Boolean> requiresStorageMotion = 
hostsForMigrationOfVM.third();
+            // Use cached compatible hosts
+            List<? extends Host> compatibleHosts = 
vmToCompatibleHostsCache.get(vm.getId());
+            Map<Host, Boolean> requiresStorageMotion = 
vmToStorageMotionCache.get(vm.getId());
+            ExcludeList excludes = vmToExcludesMap.get(vm.getId());
+
+            if (CollectionUtils.isEmpty(compatibleHosts)) {
+                continue;
+            }
+
+            ServiceOffering serviceOffering = 
vmIdServiceOfferingMap.get(vm.getId());
+            if (serviceOffering == null) {
+                continue;
+            }
 
-            for (Host destHost : compatibleDestinationHosts) {
-                if (!suitableDestinationHosts.contains(destHost) || 
cluster.getId() != destHost.getClusterId()) {
+            // Pre-calculate VM resource requirements for quick capacity 
filtering
+            long vmCpu = (long) serviceOffering.getCpu() * 
serviceOffering.getSpeed();
+            long vmMemory = serviceOffering.getRamSize() * 1024L * 1024L;
+
+            for (Host destHost : compatibleHosts) {
+                if (cluster.getId() != destHost.getClusterId()) {
                     continue;
                 }
+
+                // Check affinity constraints
+                if (excludes != null && excludes.shouldAvoid(destHost)) {
+                    continue;
+                }
+
+                // Quick capacity pre-filter: skip hosts that don't have 
enough capacity

Review Comment:
   `SkipHostsThatHaveNoCapacity()`



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -438,32 +537,104 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster 
cluster, ClusterDrsAlgorithm
             List<VirtualMachine> vmList,
             Map<Long, ServiceOffering> vmIdServiceOfferingMap,
             Map<Long, Ternary<Long, Long, Long>> hostCpuCapacityMap,
-            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap) throws 
ConfigurationException {
+            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap,
+            Map<Long, List<? extends Host>> vmToCompatibleHostsCache,
+            Map<Long, Map<Host, Boolean>> vmToStorageMotionCache,
+            Map<Long, ExcludeList> vmToExcludesMap) throws 
ConfigurationException {
+        // Pre-calculate cluster imbalance once per iteration (same for all 
VM-host combinations)
+        Double preImbalance = getClusterImbalance(cluster.getId(),
+                new ArrayList<>(hostCpuCapacityMap.values()),
+                new ArrayList<>(hostMemoryCapacityMap.values()),
+                null);
+
+        // Pre-calculate base metrics array once per iteration for optimized 
imbalance calculation
+        // This reduces complexity from O(V × H × H) to O(V × H) per iteration
+        String metricType = getClusterDrsMetric(cluster.getId());
+        Map<Long, Ternary<Long, Long, Long>> baseMetricsMap = 
"cpu".equals(metricType) ? hostCpuCapacityMap : hostMemoryCapacityMap;
+        double[] baseMetricsArray = new double[baseMetricsMap.size()];
+        Map<Long, Integer> hostIdToIndexMap = new HashMap<>();
+
+        int index = 0;
+        for (Map.Entry<Long, Ternary<Long, Long, Long>> entry : 
baseMetricsMap.entrySet()) {
+            Long hostId = entry.getKey();
+            Ternary<Long, Long, Long> metrics = entry.getValue();
+            long used = metrics.first();
+            long actualTotal = metrics.third() - metrics.second();
+            long free = actualTotal - metrics.first();
+            Double metricValue = getMetricValue(cluster.getId(), used, free, 
actualTotal, null);
+            if (metricValue != null) {
+                baseMetricsArray[index] = metricValue;
+                hostIdToIndexMap.put(hostId, index);
+                index++;
+            }
+        }
+
+        // Trim array if some values were null
+        if (index < baseMetricsArray.length) {
+            double[] trimmed = new double[index];
+            System.arraycopy(baseMetricsArray, 0, trimmed, 0, index);
+            baseMetricsArray = trimmed;
+        }
+
         double improvement = 0;
         Pair<VirtualMachine, Host> bestMigration = new Pair<>(null, null);
 
         for (VirtualMachine vm : vmList) {
             if (vm.getType().isUsedBySystem() || vm.getState() != 
VirtualMachine.State.Running ||
                     (MapUtils.isNotEmpty(vm.getDetails()) &&
-                            
vm.getDetails().get(VmDetailConstants.SKIP_DRS).equalsIgnoreCase("true"))
+                            
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))
             ) {
                 continue;
             }
-            Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, 
Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
-                    .listHostsForMigrationOfVM(
-                            vm, 0L, 500L, null, vmList);
-            List<? extends Host> compatibleDestinationHosts = 
hostsForMigrationOfVM.first().first();
-            List<? extends Host> suitableDestinationHosts = 
hostsForMigrationOfVM.second();
 
-            Map<Host, Boolean> requiresStorageMotion = 
hostsForMigrationOfVM.third();
+            // Use cached compatible hosts
+            List<? extends Host> compatibleHosts = 
vmToCompatibleHostsCache.get(vm.getId());
+            Map<Host, Boolean> requiresStorageMotion = 
vmToStorageMotionCache.get(vm.getId());
+            ExcludeList excludes = vmToExcludesMap.get(vm.getId());
+
+            if (CollectionUtils.isEmpty(compatibleHosts)) {
+                continue;
+            }
+
+            ServiceOffering serviceOffering = 
vmIdServiceOfferingMap.get(vm.getId());
+            if (serviceOffering == null) {
+                continue;
+            }
 
-            for (Host destHost : compatibleDestinationHosts) {
-                if (!suitableDestinationHosts.contains(destHost) || 
cluster.getId() != destHost.getClusterId()) {
+            // Pre-calculate VM resource requirements for quick capacity 
filtering
+            long vmCpu = (long) serviceOffering.getCpu() * 
serviceOffering.getSpeed();
+            long vmMemory = serviceOffering.getRamSize() * 1024L * 1024L;
+
+            for (Host destHost : compatibleHosts) {
+                if (cluster.getId() != destHost.getClusterId()) {
                     continue;
                 }
+
+                // Check affinity constraints

Review Comment:
   `CheckAffinityConstraints()`



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -357,10 +372,90 @@ List<Ternary<VirtualMachine, Host, Host>> 
getDrsPlan(Cluster cluster,
                     serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), 
vm.getServiceOfferingId()));
         }
 
+        // PHASE 1: Pre-compute suitable hosts (once per eligible VM - never 
changes)
+        // Use listHostsForMigrationOfVM to get hosts validated by 
getCapableSuitableHosts
+        // This ensures DRS uses the same validation as "find host for 
migration" command
+        Map<Long, List<? extends Host>> vmToCompatibleHostsCache = new 
HashMap<>();
+        Map<Long, Map<Host, Boolean>> vmToStorageMotionCache = new HashMap<>();
+
+        for (VirtualMachine vm : vmList) {
+            // Skip ineligible VMs
+            if (vm.getType().isUsedBySystem() ||
+                    vm.getState() != VirtualMachine.State.Running ||
+                    (MapUtils.isNotEmpty(vm.getDetails()) &&
+                     
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))) {
+                continue;
+            }
+
+            try {
+                // Use listHostsForMigrationOfVM to get suitable hosts 
(validated by getCapableSuitableHosts)
+                // This ensures the same validation as the "find host for 
migration" command
+                Ternary<Pair<List<? extends Host>, Integer>, List<? extends 
Host>, Map<Host, Boolean>> hostsForMigration =
+                    managementServer.listHostsForMigrationOfVM(vm, 0L, 500L, 
null, vmList);
+
+                List<? extends Host> suitableHosts = 
hostsForMigration.second(); // Get suitable hosts (validated by HostAllocator)
+                Map<Host, Boolean> requiresStorageMotion = 
hostsForMigration.third();
+
+                if (suitableHosts != null && !suitableHosts.isEmpty()) {
+                    vmToCompatibleHostsCache.put(vm.getId(), suitableHosts);
+                    vmToStorageMotionCache.put(vm.getId(), 
requiresStorageMotion);
+                }
+            } catch (Exception e) {
+                logger.debug("Could not get suitable hosts for VM {}: {}", vm, 
e.getMessage());
+            }
+        }
+
+        // Pre-fetch affinity group mappings for all eligible VMs (once, 
before iterations)
+        // This allows us to skip expensive affinity processing for VMs 
without affinity groups
+        Set<Long> vmsWithAffinityGroups = new HashSet<>();
+        for (VirtualMachine vm : vmList) {
+            if (vmToCompatibleHostsCache.containsKey(vm.getId())) {
+                // Check if VM has any affinity groups - if list is empty, VM 
has no affinity groups
+                List<AffinityGroupVMMapVO> affinityGroupMappings = 
affinityGroupVMMapDao.listByInstanceId(vm.getId());
+                if (CollectionUtils.isNotEmpty(affinityGroupMappings)) {
+                    vmsWithAffinityGroups.add(vm.getId());
+                }
+            }
+        }
+
+        // PHASE 2: Iteration loop with affinity check per iteration

Review Comment:
   `phase2Method()`.



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -438,32 +537,104 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster 
cluster, ClusterDrsAlgorithm
             List<VirtualMachine> vmList,
             Map<Long, ServiceOffering> vmIdServiceOfferingMap,
             Map<Long, Ternary<Long, Long, Long>> hostCpuCapacityMap,
-            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap) throws 
ConfigurationException {
+            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap,
+            Map<Long, List<? extends Host>> vmToCompatibleHostsCache,
+            Map<Long, Map<Host, Boolean>> vmToStorageMotionCache,
+            Map<Long, ExcludeList> vmToExcludesMap) throws 
ConfigurationException {
+        // Pre-calculate cluster imbalance once per iteration (same for all 
VM-host combinations)
+        Double preImbalance = getClusterImbalance(cluster.getId(),
+                new ArrayList<>(hostCpuCapacityMap.values()),
+                new ArrayList<>(hostMemoryCapacityMap.values()),
+                null);
+
+        // Pre-calculate base metrics array once per iteration for optimized 
imbalance calculation
+        // This reduces complexity from O(V × H × H) to O(V × H) per iteration
+        String metricType = getClusterDrsMetric(cluster.getId());
+        Map<Long, Ternary<Long, Long, Long>> baseMetricsMap = 
"cpu".equals(metricType) ? hostCpuCapacityMap : hostMemoryCapacityMap;
+        double[] baseMetricsArray = new double[baseMetricsMap.size()];
+        Map<Long, Integer> hostIdToIndexMap = new HashMap<>();
+
+        int index = 0;
+        for (Map.Entry<Long, Ternary<Long, Long, Long>> entry : 
baseMetricsMap.entrySet()) {
+            Long hostId = entry.getKey();
+            Ternary<Long, Long, Long> metrics = entry.getValue();
+            long used = metrics.first();
+            long actualTotal = metrics.third() - metrics.second();
+            long free = actualTotal - metrics.first();
+            Double metricValue = getMetricValue(cluster.getId(), used, free, 
actualTotal, null);
+            if (metricValue != null) {
+                baseMetricsArray[index] = metricValue;
+                hostIdToIndexMap.put(hostId, index);
+                index++;
+            }
+        }
+
+        // Trim array if some values were null
+        if (index < baseMetricsArray.length) {
+            double[] trimmed = new double[index];
+            System.arraycopy(baseMetricsArray, 0, trimmed, 0, index);
+            baseMetricsArray = trimmed;
+        }
+
         double improvement = 0;
         Pair<VirtualMachine, Host> bestMigration = new Pair<>(null, null);
 
         for (VirtualMachine vm : vmList) {
             if (vm.getType().isUsedBySystem() || vm.getState() != 
VirtualMachine.State.Running ||
                     (MapUtils.isNotEmpty(vm.getDetails()) &&
-                            
vm.getDetails().get(VmDetailConstants.SKIP_DRS).equalsIgnoreCase("true"))
+                            
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))
             ) {
                 continue;
             }
-            Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, 
Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
-                    .listHostsForMigrationOfVM(
-                            vm, 0L, 500L, null, vmList);
-            List<? extends Host> compatibleDestinationHosts = 
hostsForMigrationOfVM.first().first();
-            List<? extends Host> suitableDestinationHosts = 
hostsForMigrationOfVM.second();
 
-            Map<Host, Boolean> requiresStorageMotion = 
hostsForMigrationOfVM.third();
+            // Use cached compatible hosts

Review Comment:
   `UseCachedCompatibleHosts()`



##########
server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java:
##########
@@ -438,32 +537,104 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster 
cluster, ClusterDrsAlgorithm
             List<VirtualMachine> vmList,
             Map<Long, ServiceOffering> vmIdServiceOfferingMap,
             Map<Long, Ternary<Long, Long, Long>> hostCpuCapacityMap,
-            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap) throws 
ConfigurationException {
+            Map<Long, Ternary<Long, Long, Long>> hostMemoryCapacityMap,
+            Map<Long, List<? extends Host>> vmToCompatibleHostsCache,
+            Map<Long, Map<Host, Boolean>> vmToStorageMotionCache,
+            Map<Long, ExcludeList> vmToExcludesMap) throws 
ConfigurationException {
+        // Pre-calculate cluster imbalance once per iteration (same for all 
VM-host combinations)
+        Double preImbalance = getClusterImbalance(cluster.getId(),
+                new ArrayList<>(hostCpuCapacityMap.values()),
+                new ArrayList<>(hostMemoryCapacityMap.values()),
+                null);
+
+        // Pre-calculate base metrics array once per iteration for optimized 
imbalance calculation
+        // This reduces complexity from O(V × H × H) to O(V × H) per iteration
+        String metricType = getClusterDrsMetric(cluster.getId());
+        Map<Long, Ternary<Long, Long, Long>> baseMetricsMap = 
"cpu".equals(metricType) ? hostCpuCapacityMap : hostMemoryCapacityMap;
+        double[] baseMetricsArray = new double[baseMetricsMap.size()];
+        Map<Long, Integer> hostIdToIndexMap = new HashMap<>();
+
+        int index = 0;
+        for (Map.Entry<Long, Ternary<Long, Long, Long>> entry : 
baseMetricsMap.entrySet()) {
+            Long hostId = entry.getKey();
+            Ternary<Long, Long, Long> metrics = entry.getValue();
+            long used = metrics.first();
+            long actualTotal = metrics.third() - metrics.second();
+            long free = actualTotal - metrics.first();
+            Double metricValue = getMetricValue(cluster.getId(), used, free, 
actualTotal, null);
+            if (metricValue != null) {
+                baseMetricsArray[index] = metricValue;
+                hostIdToIndexMap.put(hostId, index);
+                index++;
+            }
+        }
+
+        // Trim array if some values were null
+        if (index < baseMetricsArray.length) {
+            double[] trimmed = new double[index];
+            System.arraycopy(baseMetricsArray, 0, trimmed, 0, index);
+            baseMetricsArray = trimmed;
+        }
+
         double improvement = 0;
         Pair<VirtualMachine, Host> bestMigration = new Pair<>(null, null);
 
         for (VirtualMachine vm : vmList) {
             if (vm.getType().isUsedBySystem() || vm.getState() != 
VirtualMachine.State.Running ||
                     (MapUtils.isNotEmpty(vm.getDetails()) &&
-                            
vm.getDetails().get(VmDetailConstants.SKIP_DRS).equalsIgnoreCase("true"))
+                            
"true".equalsIgnoreCase(vm.getDetails().get(VmDetailConstants.SKIP_DRS)))
             ) {
                 continue;
             }
-            Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, 
Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
-                    .listHostsForMigrationOfVM(
-                            vm, 0L, 500L, null, vmList);
-            List<? extends Host> compatibleDestinationHosts = 
hostsForMigrationOfVM.first().first();
-            List<? extends Host> suitableDestinationHosts = 
hostsForMigrationOfVM.second();
 
-            Map<Host, Boolean> requiresStorageMotion = 
hostsForMigrationOfVM.third();
+            // Use cached compatible hosts
+            List<? extends Host> compatibleHosts = 
vmToCompatibleHostsCache.get(vm.getId());
+            Map<Host, Boolean> requiresStorageMotion = 
vmToStorageMotionCache.get(vm.getId());
+            ExcludeList excludes = vmToExcludesMap.get(vm.getId());
+
+            if (CollectionUtils.isEmpty(compatibleHosts)) {
+                continue;
+            }
+
+            ServiceOffering serviceOffering = 
vmIdServiceOfferingMap.get(vm.getId());
+            if (serviceOffering == null) {
+                continue;
+            }
 
-            for (Host destHost : compatibleDestinationHosts) {
-                if (!suitableDestinationHosts.contains(destHost) || 
cluster.getId() != destHost.getClusterId()) {
+            // Pre-calculate VM resource requirements for quick capacity 
filtering
+            long vmCpu = (long) serviceOffering.getCpu() * 
serviceOffering.getSpeed();
+            long vmMemory = serviceOffering.getRamSize() * 1024L * 1024L;
+
+            for (Host destHost : compatibleHosts) {

Review Comment:
   this loop deserves its own method as well



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to