Bug 9831: Implement resourceCount periodic task that would check if the count in resource_count table matches actual resource count

status 9831: resolved fixed

   added a periodic task that does recalculation of counts. By default interval is set to 0, which will be interpreted as not to run task
This commit is contained in:
Murali Reddy 2011-10-31 18:26:21 +05:30
parent 0d4971b34e
commit e449067a4a
2 changed files with 80 additions and 20 deletions

View File

@ -284,6 +284,7 @@ public enum Config {
DefaultMaxAccountTemplates("Account Defaults", ManagementServer.class, Long.class, "max.account.templates", "20", "The default maximum number of templates that can be deployed for an account", null),
DefaultMaxAccountSnapshots("Account Defaults", ManagementServer.class, Long.class, "max.account.snapshots", "20", "The default maximum number of snapshots that can be created for an account", null),
DefaultMaxAccountVolumes("Account Defaults", ManagementServer.class, Long.class, "max.account.volumes", "20", "The default maximum number of volumes that can be created for an account", null),
ResourceCountCheckInterval("Advanced", ManagementServer.class, Long.class, "resourcecount.check.interval", "0", "Time (in seconds) to wait before retrying resource count check task. Default is 0 which is to never run the task", "Seconds"),
DirectAgentLoadSize("Advanced", ManagementServer.class, Integer.class, "direct.agent.load.size", "16", "The number of direct agents to load each time", null),
AgentLbEnable("Advanced", ClusterManager.class, Boolean.class, "agent.lb.enabled", "true", "If agent load balancing enabled in cluster setup", null),

View File

@ -21,6 +21,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
@ -58,8 +61,10 @@ import com.cloud.user.AccountVO;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
@ -108,7 +113,9 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
private ProjectDao _projectDao;
protected SearchBuilder<ResourceCountVO> ResourceCountSearch;
ScheduledExecutorService _rcExecutor;
long _resourceCountCheckInterval=0;
@Override
public String getName() {
return _name;
@ -116,6 +123,9 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
@Override
public boolean start() {
if (_resourceCountCheckInterval > 0){
_rcExecutor.scheduleAtFixedRate(new ResourceCountCheckTask(), _resourceCountCheckInterval, _resourceCountCheckInterval, TimeUnit.SECONDS);
}
return true;
}
@ -134,6 +144,10 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
ResourceCountSearch.and("domainId", ResourceCountSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
ResourceCountSearch.done();
_resourceCountCheckInterval = NumbersUtil.parseInt(_configDao.getValue(Config.ResourceCountCheckInterval.key()), 0);
if (_resourceCountCheckInterval > 0){
_rcExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ResourceCountChecker"));
}
return true;
}
@ -607,7 +621,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
@DB
protected long recalculateDomainResourceCount(long domainId, ResourceType type) {
long count=0;
long newCount=0;
Transaction txn = Transaction.currentTxn();
txn.start();
@ -618,19 +632,22 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("id", rowIdsToLock.toArray());
_resourceCountDao.lockRows(sc, null, true);
ResourceCountVO domainRC = _resourceCountDao.findByOwnerAndType(domainId, ResourceOwnerType.Domain, type);
long oldCount = domainRC.getCount();
List<DomainVO> domainChildren = _domainDao.findImmediateChildrenForParent(domainId);
// for each child domain update the resource count
if (type.supportsOwner(ResourceOwnerType.Domain)) {
//calculate project count here
if (type == ResourceType.project) {
count = count + _projectDao.countProjectsForDomain(domainId);
newCount = newCount + _projectDao.countProjectsForDomain(domainId);
}
for (DomainVO domainChild : domainChildren) {
long domainCount = recalculateDomainResourceCount(domainChild.getId(), type);
count = count + domainCount; // add the child domain count to parent domain count
newCount = newCount + domainCount; // add the child domain count to parent domain count
}
}
@ -638,22 +655,27 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
for (AccountVO account : accounts) {
long accountCount = recalculateAccountResourceCount(account.getId(), type);
count = count + accountCount; // add account's resource count to parent domain count
newCount = newCount + accountCount; // add account's resource count to parent domain count
}
}
_resourceCountDao.setResourceCount(domainId, ResourceOwnerType.Domain, type, count);
_resourceCountDao.setResourceCount(domainId, ResourceOwnerType.Domain, type, newCount);
if (oldCount != newCount) {
s_logger.info("Discrepency in the resource count " + "(original count=" + oldCount + " correct count = " +
newCount + ") for type " + type + " for domain ID " + domainId + " is fixed during resource count recalculation." );
}
} catch (Exception e) {
throw new CloudRuntimeException("Failed to update resource count for domain with Id " + domainId);
} finally {
txn.commit();
}
return count;
return newCount;
}
@DB
protected long recalculateAccountResourceCount(long accountId, ResourceType type) {
Long count=null;
Long newCount=null;
Transaction txn = Transaction.currentTxn();
txn.start();
@ -663,28 +685,34 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("accountId", accountId);
_resourceCountDao.lockRows(sc, null, true);
ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndType(accountId, ResourceOwnerType.Account, type);
long oldCount = accountRC.getCount();
if (type == Resource.ResourceType.user_vm) {
count = _userVmDao.countAllocatedVMsForAccount(accountId);
newCount = _userVmDao.countAllocatedVMsForAccount(accountId);
} else if (type == Resource.ResourceType.volume) {
count = _volumeDao.countAllocatedVolumesForAccount(accountId);
newCount = _volumeDao.countAllocatedVolumesForAccount(accountId);
long virtualRouterCount = _vmDao.countAllocatedVirtualRoutersForAccount(accountId);
count = count - virtualRouterCount; // don't count the volumes of virtual router
newCount = newCount - virtualRouterCount; // don't count the volumes of virtual router
} else if (type == Resource.ResourceType.snapshot) {
count = _snapshotDao.countSnapshotsForAccount(accountId);
newCount = _snapshotDao.countSnapshotsForAccount(accountId);
} else if (type == Resource.ResourceType.public_ip) {
count = _ipAddressDao.countAllocatedIPsForAccount(accountId);
newCount = _ipAddressDao.countAllocatedIPsForAccount(accountId);
} else if (type == Resource.ResourceType.template) {
count = _vmTemplateDao.countTemplatesForAccount(accountId);
newCount = _vmTemplateDao.countTemplatesForAccount(accountId);
} else {
throw new InvalidParameterValueException("Unsupported resource type " + type);
}
_resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (count == null) ? 0 : count.longValue());
_resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (newCount == null) ? 0 : newCount.longValue());
if (oldCount != newCount) {
s_logger.info("Discrepency in the resource count " + "(original count=" + oldCount + " correct count = " +
newCount + ") for type " + type + " for account ID " + accountId + " is fixed during resource count recalculation." );
}
txn.commit();
return (count == null) ? 0 : count.longValue();
return (newCount == null) ? 0 : newCount.longValue();
}
@Override
@ -692,4 +720,35 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager{
return _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type);
}
protected class ResourceCountCheckTask implements Runnable {
public ResourceCountCheckTask() {
}
@Override
public void run() {
s_logger.info("Running resource count check periodic task");
List<DomainVO> domains = _domainDao.findImmediateChildrenForParent(DomainVO.ROOT_DOMAIN);
// recalculateDomainResourceCount will take care of re-calculation of resource counts for sub-domains
// and accounts of the sub-domains also. so just loop through immediate children of root domain
for (Domain domain : domains ) {
for (ResourceType type : ResourceCount.ResourceType.values()) {
if (type.supportsOwner(ResourceOwnerType.Domain)) {
recalculateDomainResourceCount(domain.getId(), type);
}
}
}
// run through the accounts in the root domain
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(DomainVO.ROOT_DOMAIN);
for (AccountVO account : accounts) {
for (ResourceType type : ResourceCount.ResourceType.values()) {
if (type.supportsOwner(ResourceOwnerType.Account)) {
recalculateAccountResourceCount(account.getId(), type);
}
}
}
}
}
}