Copilot commented on code in PR #13410:
URL: https://github.com/apache/cloudstack/pull/13410#discussion_r3528316120


##########
server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java:
##########
@@ -698,14 +706,29 @@ public void updateCapacityForHost(final Host host) {
         logger.debug("Found {} VMs are Migrating from {}", 
vosMigrating.size(), host);
         vms.addAll(vosMigrating);
 
+
+        List<VMInstanceVO> vmsByLastHostId = 
_vmDao.listByLastHostId(host.getId());
+        logger.debug("Found {} VM, not running on {}", vmsByLastHostId.size(), 
host);
+
+        List<Long> allVmIds = new ArrayList<>(vms.size() + 
vmsByLastHostId.size());
+        for (VMInstanceVO vm : vms) {
+            allVmIds.add(vm.getId());
+        }
+        for (VMInstanceVO vm : vmsByLastHostId) {
+            allVmIds.add(vm.getId());
+        }
+        Map<Long, Map<String, String>> allVmDetails = allVmIds.isEmpty()
+                ? Collections.emptyMap()
+                : batchGetVmDetailsForCapacityCalculation(allVmIds);
+

Review Comment:
   `allVmIds` is currently built with *all* VMs returned by `listByLastHostId`, 
but VM details are only read for that list when `secondsSinceLastUpdate < 
_vmCapacityReleaseInterval`. This means the batch details query can become much 
larger than necessary (potentially thousands of stale VMs), which can offset 
the N+1 improvement and increase DB load.



##########
engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java:
##########
@@ -122,6 +123,31 @@ public Map<String, String> listDetailsKeyPairs(long 
resourceId, List<String> key
         return results.stream().collect(Collectors.toMap(R::getName, 
R::getValue));
     }
 
+    @Override
+    public Map<Long, Map<String, String>> listDetailsKeyPairs(List<Long> 
resourceIds, List<String> keys) {
+        if (CollectionUtils.isEmpty(resourceIds)) {
+            return new HashMap<>();
+        }
+        SearchBuilder<R> sb = createSearchBuilder();
+        sb.and("resourceId", sb.entity().getResourceId(), 
SearchCriteria.Op.IN);
+        sb.and("name", sb.entity().getName(), SearchCriteria.Op.IN);
+        sb.done();
+
+        Map<Long, Map<String, String>> result = new 
HashMap<>(resourceIds.size());
+        for (int i = 0; i < resourceIds.size(); i += IN_CLAUSE_BATCH_SIZE) {
+            List<Long> batch = resourceIds.subList(i, Math.min(i + 
IN_CLAUSE_BATCH_SIZE, resourceIds.size()));
+            SearchCriteria<R> sc = sb.create();
+            sc.setParameters("resourceId", batch.toArray());
+            sc.setParameters("name", keys.toArray());
+            List<R> results = search(sc, null);
+            for (R r : results) {
+                result.computeIfAbsent(r.getResourceId(), k -> new HashMap<>())
+                        .put(r.getName(), r.getValue());
+            }

Review Comment:
   The new batch implementation silently overwrites duplicate `(resourceId, 
name)` pairs via `Map.put(...)`, while the existing single-resource 
`listDetailsKeyPairs(long, List<String>)` uses `Collectors.toMap(...)` which 
throws on duplicate keys. This makes the batch and non-batch paths behave 
differently under the same data corruption scenario; consider failing fast here 
too for consistency.



-- 
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