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;
+ });
}
}