This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.19 by this push:
     new c98f1b8b3ca Ensure affinity groups are honored when VMs are deployed 
in parallel (#9201)
c98f1b8b3ca is described below

commit c98f1b8b3ca38cf6fa9797c66ab09943226c6f2a
Author: Vishesh <[email protected]>
AuthorDate: Mon Aug 12 17:32:16 2024 +0530

    Ensure affinity groups are honored when VMs are deployed in parallel (#9201)
---
 .../cloudstack/affinity/dao/AffinityGroupDao.java  |   3 +
 .../affinity/dao/AffinityGroupDaoImpl.java         |  12 +++
 .../cloudstack/affinity/HostAffinityProcessor.java |  39 +++++--
 .../affinity/HostAntiAffinityProcessor.java        | 114 +++++++++++++--------
 4 files changed, 116 insertions(+), 52 deletions(-)

diff --git 
a/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java
 
b/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java
index 010720ba33a..859b2921504 100644
--- 
a/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java
+++ 
b/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java
@@ -38,4 +38,7 @@ public interface AffinityGroupDao extends 
GenericDao<AffinityGroupVO, Long> {
     AffinityGroupVO findByAccountAndType(Long accountId, String string);
 
     AffinityGroupVO findDomainLevelGroupByType(Long domainId, String string);
+
+    List<AffinityGroupVO> listByIds(List<Long> ids, boolean exclusive);
+
 }
diff --git 
a/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
 
b/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
index 3bd7c6d082b..5bd598f36a0 100644
--- 
a/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
+++ 
b/engine/schema/src/main/java/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java
@@ -31,6 +31,7 @@ import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 
 public class AffinityGroupDaoImpl extends GenericDaoBase<AffinityGroupVO, 
Long> implements AffinityGroupDao {
+    private SearchBuilder<AffinityGroupVO> IdsSearch;
     private SearchBuilder<AffinityGroupVO> AccountIdSearch;
     private SearchBuilder<AffinityGroupVO> AccountIdNameSearch;
     private SearchBuilder<AffinityGroupVO> AccountIdNamesSearch;
@@ -47,6 +48,10 @@ public class AffinityGroupDaoImpl extends 
GenericDaoBase<AffinityGroupVO, Long>
 
     @PostConstruct
     protected void init() {
+        IdsSearch = createSearchBuilder();
+        IdsSearch.and("idIn", IdsSearch.entity().getId(), 
SearchCriteria.Op.IN);
+        IdsSearch.done();
+
         AccountIdSearch = createSearchBuilder();
         AccountIdSearch.and("accountId", 
AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
         AccountIdSearch.done();
@@ -158,4 +163,11 @@ public class AffinityGroupDaoImpl extends 
GenericDaoBase<AffinityGroupVO, Long>
         sc.setJoinParameters("domainTypeSearch", "domainId", domainId);
         return findOneBy(sc);
     }
+
+    @Override
+    public List<AffinityGroupVO> listByIds(List<Long> ids, boolean exclusive) {
+        SearchCriteria<AffinityGroupVO> sc = IdsSearch.create();
+        sc.setParameters("idIn", ids.toArray());
+        return lockRows(sc, null, exclusive);
+    }
 }
diff --git 
a/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
 
b/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
index 07c1dd5ff88..072eff09215 100644
--- 
a/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
+++ 
b/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
@@ -23,9 +23,14 @@ import java.util.Map;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.ArrayList;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.log4j.Logger;
 
@@ -56,9 +61,16 @@ public class HostAffinityProcessor extends 
AffinityProcessorBase implements Affi
         VirtualMachine vm = vmProfile.getVirtualMachine();
         List<AffinityGroupVMMapVO> vmGroupMappings = 
_affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
         if (CollectionUtils.isNotEmpty(vmGroupMappings)) {
-            for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
-                processAffinityGroup(vmGroupMapping, plan, vm, vmList);
-            }
+            List<Long> affinityGroupIdList = 
vmGroupMappings.stream().map(AffinityGroupVMMapVO::getAffinityGroupId).collect(Collectors.toList());
+            Transaction.execute(new TransactionCallbackNoReturn() {
+                @Override
+                public void doInTransactionWithoutResult(TransactionStatus 
status) {
+                    _affinityGroupDao.listByIds(affinityGroupIdList, true);
+                    for (AffinityGroupVMMapVO vmGroupMapping : 
vmGroupMappings) {
+                        processAffinityGroup(vmGroupMapping, plan, vm, vmList);
+                    }
+                }
+            });
         }
     }
 
@@ -132,16 +144,23 @@ public class HostAffinityProcessor extends 
AffinityProcessorBase implements Affi
         long plannedHostId = plannedDestination.getHost().getId();
         VirtualMachine vm = vmProfile.getVirtualMachine();
         List<AffinityGroupVMMapVO> vmGroupMappings = 
_affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
+        if (CollectionUtils.isEmpty(vmGroupMappings)) {
+            return true;
+        }
+        List<Long> affinityGroupIds = 
vmGroupMappings.stream().map(AffinityGroupVMMapVO::getAffinityGroupId).collect(Collectors.toList());
+        return Transaction.execute(new TransactionCallback<Boolean>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
+                    if (!checkAffinityGroup(vmGroupMapping, vm, 
plannedHostId)) {
+                        return false;
+                    }
 
-        if (CollectionUtils.isNotEmpty(vmGroupMappings)) {
-            for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
-                if (!checkAffinityGroup(vmGroupMapping, vm, plannedHostId)) {
-                    return false;
                 }
+                return true;
             }
-        }
-
-        return true;
+        });
     }
 
     /**
diff --git 
a/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
 
b/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
index 2a3c5796dda..970632906c6 100644
--- 
a/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
+++ 
b/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
@@ -19,10 +19,17 @@ package org.apache.cloudstack.affinity;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
@@ -36,7 +43,6 @@ import com.cloud.deploy.DeployDestination;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.exception.AffinityConflictException;
-import com.cloud.utils.DateUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
@@ -67,40 +73,54 @@ public class HostAntiAffinityProcessor extends 
AffinityProcessorBase implements
         VirtualMachine vm = vmProfile.getVirtualMachine();
         List<AffinityGroupVMMapVO> vmGroupMappings = 
_affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
 
-        for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
-            if (vmGroupMapping != null) {
-                AffinityGroupVO group = 
_affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId());
-
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Processing affinity group " + 
group.getName() + " for VM Id: " + vm.getId());
+        if (CollectionUtils.isEmpty(vmGroupMappings)) {
+            return;
+        }
+        List<Long> affinityGroupIds = 
vmGroupMappings.stream().map(AffinityGroupVMMapVO::getAffinityGroupId).collect(Collectors.toList());
+        Transaction.execute(new TransactionCallbackNoReturn() {
+            @Override
+            public void doInTransactionWithoutResult(TransactionStatus status) 
{
+                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
+                    processAffinityGroup(vmGroupMapping, avoid, vm);
                 }
+            }
+        });
 
-                List<Long> groupVMIds = 
_affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId());
-                groupVMIds.remove(vm.getId());
+    }
 
-                for (Long groupVMId : groupVMIds) {
-                    VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId);
-                    if (groupVM != null && !groupVM.isRemoved()) {
-                        if (groupVM.getHostId() != null) {
-                            avoid.addHost(groupVM.getHostId());
-                            if (s_logger.isDebugEnabled()) {
-                                s_logger.debug("Added host " + 
groupVM.getHostId() + " to avoid set, since VM " + groupVM.getId() + " is 
present on the host");
-                            }
-                        } else if 
(Arrays.asList(VirtualMachine.State.Starting, 
VirtualMachine.State.Stopped).contains(groupVM.getState()) && 
groupVM.getLastHostId() != null) {
-                            long secondsSinceLastUpdate = 
(DateUtil.currentGMTTime().getTime() - groupVM.getUpdateTime().getTime()) / 
1000;
-                            if (secondsSinceLastUpdate < 
_vmCapacityReleaseInterval) {
-                                avoid.addHost(groupVM.getLastHostId());
-                                if (s_logger.isDebugEnabled()) {
-                                    s_logger.debug("Added host " + 
groupVM.getLastHostId() + " to avoid set, since VM " + groupVM.getId() +
-                                        " is present on the host, in Stopped 
state but has reserved capacity");
-                                }
-                            }
+    protected void processAffinityGroup(AffinityGroupVMMapVO vmGroupMapping, 
ExcludeList avoid, VirtualMachine vm) {
+        if (vmGroupMapping != null) {
+            AffinityGroupVO group = 
_affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId());
+
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Processing affinity group " + group.getName() 
+ " for VM Id: " + vm.getId());
+            }
+
+            List<Long> groupVMIds = 
_affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId());
+            groupVMIds.remove(vm.getId());
+
+            for (Long groupVMId : groupVMIds) {
+                VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId);
+                if (groupVM != null && !groupVM.isRemoved()) {
+                    if (groupVM.getHostId() != null) {
+                        avoid.addHost(groupVM.getHostId());
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Added host " + groupVM.getHostId() 
+ " to avoid set, since VM " + groupVM.getId() + " is present on the host");
+                        }
+                    }
+                } else if (Arrays.asList(VirtualMachine.State.Starting, 
VirtualMachine.State.Stopped).contains(groupVM.getState()) && 
groupVM.getLastHostId() != null) {
+                    long secondsSinceLastUpdate = 
(DateUtil.currentGMTTime().getTime() - groupVM.getUpdateTime().getTime()) / 
1000;
+                    if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) {
+                        avoid.addHost(groupVM.getLastHostId());
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Added host " + 
groupVM.getLastHostId() + " to avoid set, since VM " + groupVM.getId() +
+                                    " is present on the host, in Stopped state 
but has reserved capacity");
                         }
                     }
                 }
             }
         }
-
     }
 
     @Override
@@ -121,25 +141,35 @@ public class HostAntiAffinityProcessor extends 
AffinityProcessorBase implements
         VirtualMachine vm = vmProfile.getVirtualMachine();
 
         List<AffinityGroupVMMapVO> vmGroupMappings = 
_affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
+        if (CollectionUtils.isEmpty(vmGroupMappings)) {
+            return true;
+        }
 
-        for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
-            // if more than 1 VM's are present in the group then check for
-            // conflict due to parallel deployment
-            List<Long> groupVMIds = 
_affinityGroupVMMapDao.listVmIdsByAffinityGroup(vmGroupMapping.getAffinityGroupId());
-            groupVMIds.remove(vm.getId());
-
-            for (Long groupVMId : groupVMIds) {
-                VMReservationVO vmReservation = 
_reservationDao.findByVmId(groupVMId);
-                if (vmReservation != null && vmReservation.getHostId() != null 
&& vmReservation.getHostId().equals(plannedHostId)) {
-                    if (s_logger.isDebugEnabled()) {
-                        s_logger.debug("Planned destination for VM " + 
vm.getId() + " conflicts with an existing VM " + vmReservation.getVmId() +
-                            " reserved on the same host " + plannedHostId);
+        List<Long> affinityGroupIds = 
vmGroupMappings.stream().map(AffinityGroupVMMapVO::getAffinityGroupId).collect(Collectors.toList());
+        return Transaction.execute(new TransactionCallback<Boolean>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
+                    // if more than 1 VM's are present in the group then check 
for
+                    // conflict due to parallel deployment
+                    List<Long> groupVMIds = 
_affinityGroupVMMapDao.listVmIdsByAffinityGroup(vmGroupMapping.getAffinityGroupId());
+                    groupVMIds.remove(vm.getId());
+
+                    for (Long groupVMId : groupVMIds) {
+                        VMReservationVO vmReservation = 
_reservationDao.findByVmId(groupVMId);
+                        if (vmReservation != null && vmReservation.getHostId() 
!= null && vmReservation.getHostId().equals(plannedHostId)) {
+                            if (s_logger.isDebugEnabled()) {
+                                s_logger.debug("Planned destination for VM " + 
vm.getId() + " conflicts with an existing VM " + vmReservation.getVmId() +
+                                        " reserved on the same host " + 
plannedHostId);
+                            }
+                            return false;
+                        }
                     }
-                    return false;
                 }
+                return true;
             }
-        }
-        return true;
+        });
     }
 
 }

Reply via email to