Speedup resource count calculation (#8903)

* Speed up resource count calculation

* Refactor resource count calculation

* Start transaction for updateCountByDeltaForIds
This commit is contained in:
Vishesh 2024-04-17 14:21:30 +05:30 committed by GitHub
parent 090c1e38a6
commit ebaf5a47b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 149 additions and 91 deletions

View File

@ -49,10 +49,15 @@ public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
ResourceCountVO findByOwnerAndTypeAndTag(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag); ResourceCountVO findByOwnerAndTypeAndTag(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag);
List<ResourceCountVO> findByOwnersAndTypeAndTag(List<Long> ownerIdList, ResourceOwnerType ownerType,
ResourceType type, String tag);
List<ResourceCountVO> listResourceCountByOwnerType(ResourceOwnerType ownerType); List<ResourceCountVO> listResourceCountByOwnerType(ResourceOwnerType ownerType);
Set<Long> listAllRowsToUpdate(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag); Set<Long> listAllRowsToUpdate(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag);
boolean updateCountByDeltaForIds(List<Long> ids, boolean increment, long delta);
Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type, String tag); Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type, String tag);
long removeEntriesByOwner(long ownerId, ResourceOwnerType ownerType); long removeEntriesByOwner(long ownerId, ResourceOwnerType ownerType);
@ -72,4 +77,6 @@ public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
long countMemoryAllocatedToAccount(long accountId); long countMemoryAllocatedToAccount(long accountId);
void removeResourceCountsForNonMatchingTags(Long ownerId, ResourceOwnerType ownerType, List<ResourceType> types, List<String> tags); void removeResourceCountsForNonMatchingTags(Long ownerId, ResourceOwnerType ownerType, List<ResourceType> types, List<String> tags);
List<ResourceCountVO> lockRows(Set<Long> ids);
} }

View File

@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
@ -56,27 +57,30 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
private final SearchBuilder<ResourceCountVO> TypeSearch; private final SearchBuilder<ResourceCountVO> TypeSearch;
private final SearchBuilder<ResourceCountVO> TypeNullTagSearch; private final SearchBuilder<ResourceCountVO> TypeNullTagSearch;
private final SearchBuilder<ResourceCountVO> NonMatchingTagsSearch; private final SearchBuilder<ResourceCountVO> NonMatchingTagsSearch;
private final SearchBuilder<ResourceCountVO> AccountSearch; private final SearchBuilder<ResourceCountVO> AccountSearch;
private final SearchBuilder<ResourceCountVO> DomainSearch; private final SearchBuilder<ResourceCountVO> DomainSearch;
private final SearchBuilder<ResourceCountVO> IdsSearch;
@Inject @Inject
private DomainDao _domainDao; private DomainDao _domainDao;
@Inject @Inject
private AccountDao _accountDao; private AccountDao _accountDao;
protected static final String INCREMENT_COUNT_BY_IDS_SQL = "UPDATE `cloud`.`resource_count` SET `count` = `count` + ? WHERE `id` IN (?)";
protected static final String DECREMENT_COUNT_BY_IDS_SQL = "UPDATE `cloud`.`resource_count` SET `count` = `count` - ? WHERE `id` IN (?)";
public ResourceCountDaoImpl() { public ResourceCountDaoImpl() {
TypeSearch = createSearchBuilder(); TypeSearch = createSearchBuilder();
TypeSearch.and("type", TypeSearch.entity().getType(), SearchCriteria.Op.EQ); TypeSearch.and("type", TypeSearch.entity().getType(), SearchCriteria.Op.EQ);
TypeSearch.and("accountId", TypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ); TypeSearch.and("accountId", TypeSearch.entity().getAccountId(), SearchCriteria.Op.IN);
TypeSearch.and("domainId", TypeSearch.entity().getDomainId(), SearchCriteria.Op.EQ); TypeSearch.and("domainId", TypeSearch.entity().getDomainId(), SearchCriteria.Op.IN);
TypeSearch.and("tag", TypeSearch.entity().getTag(), SearchCriteria.Op.EQ); TypeSearch.and("tag", TypeSearch.entity().getTag(), SearchCriteria.Op.EQ);
TypeSearch.done(); TypeSearch.done();
TypeNullTagSearch = createSearchBuilder(); TypeNullTagSearch = createSearchBuilder();
TypeNullTagSearch.and("type", TypeNullTagSearch.entity().getType(), SearchCriteria.Op.EQ); TypeNullTagSearch.and("type", TypeNullTagSearch.entity().getType(), SearchCriteria.Op.EQ);
TypeNullTagSearch.and("accountId", TypeNullTagSearch.entity().getAccountId(), SearchCriteria.Op.EQ); TypeNullTagSearch.and("accountId", TypeNullTagSearch.entity().getAccountId(), SearchCriteria.Op.IN);
TypeNullTagSearch.and("domainId", TypeNullTagSearch.entity().getDomainId(), SearchCriteria.Op.EQ); TypeNullTagSearch.and("domainId", TypeNullTagSearch.entity().getDomainId(), SearchCriteria.Op.IN);
TypeNullTagSearch.and("tag", TypeNullTagSearch.entity().getTag(), SearchCriteria.Op.NULL); TypeNullTagSearch.and("tag", TypeNullTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
TypeNullTagSearch.done(); TypeNullTagSearch.done();
@ -90,6 +94,10 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
AccountSearch = createSearchBuilder(); AccountSearch = createSearchBuilder();
DomainSearch = createSearchBuilder(); DomainSearch = createSearchBuilder();
IdsSearch = createSearchBuilder();
IdsSearch.and("id", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
IdsSearch.done();
} }
@PostConstruct @PostConstruct
@ -109,6 +117,19 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
@Override @Override
public ResourceCountVO findByOwnerAndTypeAndTag(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag) { public ResourceCountVO findByOwnerAndTypeAndTag(long ownerId, ResourceOwnerType ownerType, ResourceType type, String tag) {
List<ResourceCountVO> resourceCounts = findByOwnersAndTypeAndTag(List.of(ownerId), ownerType, type, tag);
if (CollectionUtils.isNotEmpty(resourceCounts)) {
return resourceCounts.get(0);
} else {
return null;
}
}
@Override
public List<ResourceCountVO> findByOwnersAndTypeAndTag(List<Long> ownerIdList, ResourceOwnerType ownerType, ResourceType type, String tag) {
if (CollectionUtils.isEmpty(ownerIdList)) {
return new ArrayList<>();
}
SearchCriteria<ResourceCountVO> sc = tag != null ? TypeSearch.create() : TypeNullTagSearch.create(); SearchCriteria<ResourceCountVO> sc = tag != null ? TypeSearch.create() : TypeNullTagSearch.create();
sc.setParameters("type", type); sc.setParameters("type", type);
if (tag != null) { if (tag != null) {
@ -116,13 +137,13 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
} }
if (ownerType == ResourceOwnerType.Account) { if (ownerType == ResourceOwnerType.Account) {
sc.setParameters("accountId", ownerId); sc.setParameters("accountId", ownerIdList.toArray());
return findOneIncludingRemovedBy(sc); return listIncludingRemovedBy(sc);
} else if (ownerType == ResourceOwnerType.Domain) { } else if (ownerType == ResourceOwnerType.Domain) {
sc.setParameters("domainId", ownerId); sc.setParameters("domainId", ownerIdList.toArray());
return findOneIncludingRemovedBy(sc); return listIncludingRemovedBy(sc);
} else { } else {
return null; return new ArrayList<>();
} }
} }
@ -154,6 +175,26 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
return update(resourceCountVO.getId(), resourceCountVO); return update(resourceCountVO.getId(), resourceCountVO);
} }
@Override
public boolean updateCountByDeltaForIds(List<Long> ids, boolean increment, long delta) {
if (CollectionUtils.isEmpty(ids)) {
return false;
}
String updateSql = increment ? INCREMENT_COUNT_BY_IDS_SQL : DECREMENT_COUNT_BY_IDS_SQL;
String poolIdsInStr = ids.stream().map(String::valueOf).collect(Collectors.joining(",", "(", ")"));
String sql = updateSql.replace("(?)", poolIdsInStr);
final TransactionLegacy txn = TransactionLegacy.currentTxn();
try(PreparedStatement pstmt = txn.prepareStatement(sql);) {
pstmt.setLong(1, delta);
pstmt.executeUpdate();
return true;
} catch (SQLException e) {
throw new CloudRuntimeException(e);
}
}
@Override @Override
public Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type, String tag) { public Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type, String tag) {
Set<Long> rowIds = new HashSet<Long>(); Set<Long> rowIds = new HashSet<Long>();
@ -345,4 +386,14 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
} }
remove(sc); remove(sc);
} }
@Override
public List<ResourceCountVO> lockRows(Set<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return new ArrayList<>();
}
SearchCriteria<ResourceCountVO> sc = IdsSearch.create();
sc.setParameters("id", ids.toArray());
return lockRows(sc, null, true);
}
} }

View File

@ -31,4 +31,5 @@ public interface ReservationDao extends GenericDao<ReservationVO, Long> {
void setResourceId(Resource.ResourceType type, Long resourceId); void setResourceId(Resource.ResourceType type, Long resourceId);
List<Long> getResourceIds(long accountId, Resource.ResourceType type); List<Long> getResourceIds(long accountId, Resource.ResourceType type);
List<ReservationVO> getReservationsForAccount(long accountId, Resource.ResourceType type, String tag); List<ReservationVO> getReservationsForAccount(long accountId, Resource.ResourceType type, String tag);
void removeByIds(List<Long> reservationIds);
} }

View File

@ -29,6 +29,7 @@ import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import org.apache.cloudstack.user.ResourceReservation; import org.apache.cloudstack.user.ResourceReservation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -40,6 +41,7 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
private static final String RESOURCE_ID = "resourceId"; private static final String RESOURCE_ID = "resourceId";
private static final String ACCOUNT_ID = "accountId"; private static final String ACCOUNT_ID = "accountId";
private static final String DOMAIN_ID = "domainId"; private static final String DOMAIN_ID = "domainId";
private static final String IDS = "ids";
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeSearch; private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeSearch;
private final SearchBuilder<ReservationVO> listAccountAndTypeSearch; private final SearchBuilder<ReservationVO> listAccountAndTypeSearch;
private final SearchBuilder<ReservationVO> listAccountAndTypeAndNoTagSearch; private final SearchBuilder<ReservationVO> listAccountAndTypeAndNoTagSearch;
@ -47,6 +49,7 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
private final SearchBuilder<ReservationVO> listDomainAndTypeSearch; private final SearchBuilder<ReservationVO> listDomainAndTypeSearch;
private final SearchBuilder<ReservationVO> listDomainAndTypeAndNoTagSearch; private final SearchBuilder<ReservationVO> listDomainAndTypeAndNoTagSearch;
private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeAndNoTagSearch; private final SearchBuilder<ReservationVO> listResourceByAccountAndTypeAndNoTagSearch;
private final SearchBuilder<ReservationVO> listIdsSearch;
public ReservationDaoImpl() { public ReservationDaoImpl() {
@ -87,6 +90,10 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
listDomainAndTypeAndNoTagSearch.and(RESOURCE_TYPE, listDomainAndTypeAndNoTagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); listDomainAndTypeAndNoTagSearch.and(RESOURCE_TYPE, listDomainAndTypeAndNoTagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
listDomainAndTypeAndNoTagSearch.and(RESOURCE_TAG, listDomainAndTypeAndNoTagSearch.entity().getTag(), SearchCriteria.Op.NULL); listDomainAndTypeAndNoTagSearch.and(RESOURCE_TAG, listDomainAndTypeAndNoTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
listDomainAndTypeAndNoTagSearch.done(); listDomainAndTypeAndNoTagSearch.done();
listIdsSearch = createSearchBuilder();
listIdsSearch.and(IDS, listIdsSearch.entity().getId(), SearchCriteria.Op.IN);
listIdsSearch.done();
} }
@Override @Override
@ -161,4 +168,13 @@ public class ReservationDaoImpl extends GenericDaoBase<ReservationVO, Long> impl
} }
return listBy(sc); return listBy(sc);
} }
@Override
public void removeByIds(List<Long> reservationIds) {
if (CollectionUtils.isNotEmpty(reservationIds)) {
SearchCriteria<ReservationVO> sc = listIdsSearch.create();
sc.setParameters(IDS, reservationIds.toArray());
remove(sc);
}
}
} }

View File

@ -21,6 +21,7 @@ import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -203,17 +204,12 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void removeResourceReservationIfNeededAndIncrementResourceCount(final long accountId, final ResourceType type, String tag, final long numToIncrement) { protected void removeResourceReservationIfNeededAndIncrementResourceCount(final long accountId, final ResourceType type, String tag, final long numToIncrement) {
Object obj = CallContext.current().getContextParameter(CheckedReservation.getResourceReservationContextParameterKey(type));
List<Long> reservationIds = (List<Long>)obj; // This complains an unchecked casting warning
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() { Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
@Override @Override
public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException { public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException {
reservationDao.removeByIds(reservationIds);
Object obj = CallContext.current().getContextParameter(CheckedReservation.getResourceReservationContextParameterKey(type));
if (obj instanceof List) {
List<Long> reservationIds = (List<Long>)obj; // This complains an unchecked casting warning
for (Long reservationId : reservationIds) {
reservationDao.remove(reservationId);
}
}
if (!updateResourceCountForAccount(accountId, type, tag, true, numToIncrement)) { if (!updateResourceCountForAccount(accountId, type, tag, true, numToIncrement)) {
// we should fail the operation (resource creation) when failed to update the resource count // we should fail the operation (resource creation) when failed to update the resource count
throw new CloudRuntimeException("Failed to increment resource count of type " + type + " for account id=" + accountId); throw new CloudRuntimeException("Failed to increment resource count of type " + type + " for account id=" + accountId);
@ -579,13 +575,6 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
return _resourceCountDao.lockRows(sc, null, true); return _resourceCountDao.lockRows(sc, null, true);
} }
private List<ResourceCountVO> lockDomainRows(long domainId, final ResourceType type, String tag) {
Set<Long> rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(domainId, ResourceOwnerType.Domain, type, tag);
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("id", rowIdsToLock.toArray());
return _resourceCountDao.lockRows(sc, null, true);
}
@Override @Override
public long findDefaultResourceLimitForDomain(ResourceType resourceType) { public long findDefaultResourceLimitForDomain(ResourceType resourceType) {
Long resourceLimit = null; Long resourceLimit = null;
@ -613,13 +602,11 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
} }
@Override @Override
@DB
public void checkResourceLimit(final Account account, final ResourceType type, long... count) throws ResourceAllocationException { public void checkResourceLimit(final Account account, final ResourceType type, long... count) throws ResourceAllocationException {
checkResourceLimitWithTag(account, type, null, count); checkResourceLimitWithTag(account, type, null, count);
} }
@Override @Override
@DB
public void checkResourceLimitWithTag(final Account account, final ResourceType type, String tag, long... count) throws ResourceAllocationException { public void checkResourceLimitWithTag(final Account account, final ResourceType type, String tag, long... count) throws ResourceAllocationException {
final long numResources = ((count.length == 0) ? 1 : count[0]); final long numResources = ((count.length == 0) ? 1 : count[0]);
Project project = null; Project project = null;
@ -1124,7 +1111,6 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
return recalculateResourceCount(accountId, domainId, typeId, null); return recalculateResourceCount(accountId, domainId, typeId, null);
} }
@DB
protected boolean updateResourceCountForAccount(final long accountId, final ResourceType type, String tag, final boolean increment, final long delta) { protected boolean updateResourceCountForAccount(final long accountId, final ResourceType type, String tag, final boolean increment, final long delta) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
String convertedDelta = String.valueOf(delta); String convertedDelta = String.valueOf(delta);
@ -1134,25 +1120,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
String typeStr = StringUtils.isNotEmpty(tag) ? String.format("%s (tag: %s)", type, tag) : type.getName(); String typeStr = StringUtils.isNotEmpty(tag) ? String.format("%s (tag: %s)", type, tag) : type.getName();
logger.debug("Updating resource Type = " + typeStr + " count for Account = " + accountId + " Operation = " + (increment ? "increasing" : "decreasing") + " Amount = " + convertedDelta); logger.debug("Updating resource Type = " + typeStr + " count for Account = " + accountId + " Operation = " + (increment ? "increasing" : "decreasing") + " Amount = " + convertedDelta);
} }
try { Set<Long> rowIdsToUpdate = _resourceCountDao.listAllRowsToUpdate(accountId, ResourceOwnerType.Account, type, tag);
return Transaction.execute(new TransactionCallback<Boolean>() { return _resourceCountDao.updateCountByDeltaForIds(new ArrayList<>(rowIdsToUpdate), increment, delta);
@Override
public Boolean doInTransaction(TransactionStatus status) {
boolean result = true;
List<ResourceCountVO> rowsToUpdate = lockAccountAndOwnerDomainRows(accountId, type, tag);
for (ResourceCountVO rowToUpdate : rowsToUpdate) {
if (!_resourceCountDao.updateById(rowToUpdate.getId(), increment, delta)) {
logger.trace("Unable to update resource count for the row " + rowToUpdate);
result = false;
}
}
return result;
}
});
} catch (Exception ex) {
logger.error("Failed to update resource count for account id=" + accountId);
return false;
}
} }
/** /**
@ -1163,43 +1132,63 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
* @param type the resource type to do the recalculation for * @param type the resource type to do the recalculation for
* @return the resulting new resource count * @return the resulting new resource count
*/ */
@DB
protected long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) { protected long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) {
return Transaction.execute(new TransactionCallback<Long>() { List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
@Override List<DomainVO> childDomains = _domainDao.findImmediateChildrenForParent(domainId);
public Long doInTransaction(TransactionStatus status) {
long newResourceCount = 0;
lockDomainRows(domainId, type, tag);
ResourceCountVO domainRC = _resourceCountDao.findByOwnerAndTypeAndTag(domainId, ResourceOwnerType.Domain, type, tag);
long oldResourceCount = domainRC.getCount();
List<DomainVO> domainChildren = _domainDao.findImmediateChildrenForParent(domainId); if (CollectionUtils.isNotEmpty(childDomains)) {
// for each child domain update the resource count for (DomainVO childDomain : childDomains) {
recalculateDomainResourceCount(childDomain.getId(), type, tag);
}
}
if (CollectionUtils.isNotEmpty(accounts)) {
for (AccountVO account : accounts) {
recalculateAccountResourceCount(account.getId(), type, tag);
}
}
return Transaction.execute((TransactionCallback<Long>) status -> {
long newResourceCount = 0L;
List<Long> domainIdList = childDomains.stream().map(DomainVO::getId).collect(Collectors.toList());
domainIdList.add(domainId);
List<Long> accountIdList = accounts.stream().map(AccountVO::getId).collect(Collectors.toList());
List<ResourceCountVO> domainRCList = _resourceCountDao.findByOwnersAndTypeAndTag(domainIdList, ResourceOwnerType.Domain, type, tag);
List<ResourceCountVO> accountRCList = _resourceCountDao.findByOwnersAndTypeAndTag(accountIdList, ResourceOwnerType.Account, type, tag);
Set<Long> rowIdsToLock = new HashSet<>();
if (domainRCList != null) {
rowIdsToLock.addAll(domainRCList.stream().map(ResourceCountVO::getId).collect(Collectors.toList()));
}
if (accountRCList != null) {
rowIdsToLock.addAll(accountRCList.stream().map(ResourceCountVO::getId).collect(Collectors.toList()));
}
// lock the resource count rows for current domain, immediate child domain & accounts
List<ResourceCountVO> resourceCounts = _resourceCountDao.lockRows(rowIdsToLock);
long oldResourceCount = 0L;
ResourceCountVO domainRC = null;
// calculate project count here // calculate project count here
if (type == ResourceType.project) { if (type == ResourceType.project) {
newResourceCount += _projectDao.countProjectsForDomain(domainId); newResourceCount += _projectDao.countProjectsForDomain(domainId);
} }
for (DomainVO childDomain : domainChildren) { for (ResourceCountVO resourceCount : resourceCounts) {
long childDomainResourceCount = recalculateDomainResourceCount(childDomain.getId(), type, tag); if (resourceCount.getResourceOwnerType() == ResourceOwnerType.Domain && resourceCount.getDomainId() == domainId) {
newResourceCount += childDomainResourceCount; // add the child domain count to parent domain count oldResourceCount = resourceCount.getCount();
domainRC = resourceCount;
} else {
newResourceCount += resourceCount.getCount();
} }
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
for (AccountVO account : accounts) {
long accountResourceCount = recalculateAccountResourceCount(account.getId(), type, tag);
newResourceCount += accountResourceCount; // add account's resource count to parent domain count
} }
_resourceCountDao.setResourceCount(domainId, ResourceOwnerType.Domain, type, tag, newResourceCount);
if (oldResourceCount != newResourceCount) { if (oldResourceCount != newResourceCount) {
domainRC.setCount(newResourceCount);
_resourceCountDao.update(domainRC.getId(), domainRC);
logger.warn("Discrepency in the resource count has been detected " + "(original count = " + oldResourceCount + " correct count = " + newResourceCount + ") for Type = " + type logger.warn("Discrepency in the resource count has been detected " + "(original count = " + oldResourceCount + " correct count = " + newResourceCount + ") for Type = " + type
+ " for Domain ID = " + domainId + " is fixed during resource count recalculation."); + " for Domain ID = " + domainId + " is fixed during resource count recalculation.");
} }
return newResourceCount; return newResourceCount;
}
}); });
} }
@ -1238,16 +1227,10 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
final ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndTypeAndTag(accountId, ResourceOwnerType.Account, type, tag); final ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndTypeAndTag(accountId, ResourceOwnerType.Account, type, tag);
if (accountRC != null) { if (accountRC != null) {
oldCount = accountRC.getCount(); oldCount = accountRC.getCount();
}
if (newCount == null || !newCount.equals(oldCount)) { if (newCount == null || !newCount.equals(oldCount)) {
Transaction.execute(new TransactionCallbackNoReturn() { accountRC.setCount((newCount == null) ? 0 : newCount);
@Override _resourceCountDao.update(accountRC.getId(), accountRC);
public void doInTransactionWithoutResult(TransactionStatus status) {
lockAccountAndOwnerDomainRows(accountId, type, tag);
_resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, tag, (newCount == null) ? 0 : newCount);
} }
});
} }
// No need to log message for primary and secondary storage because both are recalculating the // No need to log message for primary and secondary storage because both are recalculating the