From 12cb54dc80958f6859b30856794e55edd8d0332d Mon Sep 17 00:00:00 2001 From: Ivan Kudryavtsev Date: Mon, 13 Nov 2017 13:46:02 +0700 Subject: [PATCH 1/2] CLOUDSTACK-10140 Fixed Conflicts: services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java --- .../storage/template/TemplateLocation.java | 53 +++++++++++++------ .../resource/NfsSecondaryStorageResource.java | 8 +-- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/core/src/com/cloud/storage/template/TemplateLocation.java b/core/src/com/cloud/storage/template/TemplateLocation.java index e52a635dc68f..d10d05ae9711 100644 --- a/core/src/com/cloud/storage/template/TemplateLocation.java +++ b/core/src/com/cloud/storage/template/TemplateLocation.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.Properties; +import java.util.Arrays; import org.apache.log4j.Logger; @@ -81,12 +82,12 @@ public boolean purge() { boolean purged = true; String[] files = _storage.listFiles(_templatePath); for (String file : files) { - boolean r = _storage.delete(file); - if (!r) { + boolean isRemoved = _storage.delete(file); + if (!isRemoved) { purged = false; } if (s_logger.isDebugEnabled()) { - s_logger.debug((r ? "R" : "Unable to r") + "emove " + file); + s_logger.debug((isRemoved ? "Removed " : "Unable to remove") + file); } } @@ -97,43 +98,60 @@ public boolean load() throws IOException { try (FileInputStream strm = new FileInputStream(_file);) { _props.load(strm); } catch (IOException e) { - s_logger.warn("Unable to load the template properties", e); + s_logger.warn("Unable to load the template properties for '" + _file + "': ", e); } for (ImageFormat format : ImageFormat.values()) { - String ext = _props.getProperty(format.getFileExtension()); + String currentExtension = format.getFileExtension(); + String ext = _props.getProperty(currentExtension); if (ext != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("File extension '" + currentExtension + "' was found in '" + _file + "'."); + } FormatInfo info = new FormatInfo(); info.format = format; - info.filename = _props.getProperty(format.getFileExtension() + ".filename"); + info.filename = _props.getProperty(currentExtension + ".filename"); if (info.filename == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Property '" + currentExtension + ".filename' was not found in '" + _file + "'. Current format is ignored."); + } continue; } - info.size = NumbersUtil.parseLong(_props.getProperty(format.getFileExtension() + ".size"), -1); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Property '" + currentExtension + ".filename' was found in '" + _file + "'. Current format will be parsed."); + } + info.size = NumbersUtil.parseLong(_props.getProperty(currentExtension + ".size"), -1); _props.setProperty("physicalSize", Long.toString(info.size)); - info.virtualSize = NumbersUtil.parseLong(_props.getProperty(format.getFileExtension() + ".virtualsize"), -1); + info.virtualSize = NumbersUtil.parseLong(_props.getProperty(currentExtension + ".virtualsize"), -1); _formats.add(info); if (!checkFormatValidity(info)) { _isCorrupted = true; s_logger.warn("Cleaning up inconsistent information for " + format); } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Format extension '" + currentExtension + "' wasn't found in '" + _file + "'."); + } } } if (_props.getProperty("uniquename") == null || _props.getProperty("virtualsize") == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Property 'uniquename' or 'virtualsize' weren't found in '" + _file + "'. Loading failed."); + } return false; } - return (_formats.size() > 0); } public boolean save() { for (FormatInfo info : _formats) { - _props.setProperty(info.format.getFileExtension(), "true"); - _props.setProperty(info.format.getFileExtension() + ".filename", info.filename); - _props.setProperty(info.format.getFileExtension() + ".size", Long.toString(info.size)); - _props.setProperty(info.format.getFileExtension() + ".virtualsize", Long.toString(info.virtualSize)); + String formatExtension = info.format.getFileExtension(); + _props.setProperty(formatExtension, "true"); + _props.setProperty(formatExtension + ".filename", info.filename); + _props.setProperty(formatExtension + ".size", Long.toString(info.size)); + _props.setProperty(formatExtension + ".virtualsize", Long.toString(info.virtualSize)); } try (FileOutputStream strm = new FileOutputStream(_file);) { _props.store(strm, ""); @@ -205,10 +223,11 @@ protected FormatInfo deleteFormat(ImageFormat format) { FormatInfo info = it.next(); if (info.format == format) { it.remove(); - _props.remove(format.getFileExtension()); - _props.remove(format.getFileExtension() + ".filename"); - _props.remove(format.getFileExtension() + ".size"); - _props.remove(format.getFileExtension() + ".virtualsize"); + String formatExtension = format.getFileExtension(); + _props.remove(formatExtension); + for(String propertySuffix : Arrays.asList("filename","size","virtualsize")) { + _props.remove(formatExtension + "." + propertySuffix); + } return info; } } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index eb6f220f7ca8..54c6b99cde96 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -521,12 +521,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj bufferWriter.write("uniquename=" + destData.getName()); bufferWriter.write("\n"); bufferWriter.write("filename=" + fileName); - bufferWriter.write("\n"); - long size = _storage.getSize(destFileFullPath); - bufferWriter.write("size=" + size); - bufferWriter.close(); - writer.close(); - + } + try { /** * Snapshots might be in either QCOW2 or RAW image format * From fd38223571510c7e1675ee6d87239da23f104ed9 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 17 Dec 2017 21:14:17 +0700 Subject: [PATCH 2/2] CLOUDSTACK-10188 Code cleanup, refactored methods, removed copy-pasts, improved logging, improved log levels. Fixed primary storage resource calculation. --- .../com/cloud/user/ResourceLimitService.java | 2 +- .../orchestration/VolumeOrchestrator.java | 3 +- .../ResourceLimitManagerImpl.java | 355 ++++++++++-------- .../cloud/storage/VolumeApiServiceImpl.java | 8 +- .../storage/snapshot/SnapshotManagerImpl.java | 3 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 73 ++-- 6 files changed, 232 insertions(+), 212 deletions(-) diff --git a/api/src/com/cloud/user/ResourceLimitService.java b/api/src/com/cloud/user/ResourceLimitService.java index 0ec2dc1c758e..5386a6b34c37 100644 --- a/api/src/com/cloud/user/ResourceLimitService.java +++ b/api/src/com/cloud/user/ResourceLimitService.java @@ -28,7 +28,7 @@ public interface ResourceLimitService { static final ConfigKey ResourceCountCheckInterval = new ConfigKey("Advanced", Long.class, "resourcecount.check.interval", "300", - "Time (in seconds) to wait before retrying resource count check task. Default is 300, Setting this to 0 will not run the task", false); + "Time (in seconds) to wait before running resource recalculation and fixing task. Default is 300 seconds, Setting this to 0 disables execution of the task", false); /** * Updates an existing resource limit with the specified details. If a limit doesn't exist, will create one. diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 7669b3b98a93..4a85346495e1 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -1571,8 +1571,7 @@ public void destroyVolume(Volume volume) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplay()); - //FIXME - why recalculate and not decrement - _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), ResourceType.primary_storage.getOrdinal()); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplay(), new Long(volume.getSize())); } catch (Exception e) { s_logger.debug("Failed to destroy volume" + volume.getId(), e); throw new CloudRuntimeException("Failed to destroy volume" + volume.getId(), e); diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 55ed60b38048..b3025b1fab20 100644 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -26,18 +26,17 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.Configurable; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; @@ -109,8 +108,7 @@ import com.cloud.vm.dao.VMInstanceDao; @Component -@Local(value = {ResourceLimitService.class}) -public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLimitService, Configurable{ +public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLimitService, Configurable { public static final Logger s_logger = Logger.getLogger(ResourceLimitManagerImpl.class); @Inject @@ -413,6 +411,81 @@ public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type) return max; } + private void checkDomainResourceLimit(final Account account, final Project project, final ResourceType type, long numResources) throws ResourceAllocationException { + // check all domains in the account's domain hierarchy + Long domainId = null; + if (project != null) { + domainId = project.getDomainId(); + } else { + domainId = account.getDomainId(); + } + + while (domainId != null) { + DomainVO domain = _domainDao.findById(domainId); + // no limit check if it is ROOT domain + if (domainId != Domain.ROOT_DOMAIN) { + long domainResourceLimit = findCorrectResourceLimitForDomain(domain, type); + long currentDomainResourceCount = _resourceCountDao.getResourceCount(domainId, ResourceOwnerType.Domain, type); + long requestedDomainResourceCount = currentDomainResourceCount + numResources; + String messageSuffix = " domain resource limits of Type '" + type + "'" + + " for Domain Id = " + domainId + + " is exceeded: Domain Resource Limit = " + domainResourceLimit + + ", Current Domain Resource Amount = " + currentDomainResourceCount + + ", Requested Resource Amount = " + numResources + "."; + + if(s_logger.isDebugEnabled()) { + s_logger.debug("Checking if" + messageSuffix); + } + + if (domainResourceLimit != Resource.RESOURCE_UNLIMITED && requestedDomainResourceCount > domainResourceLimit) { + String message = "Maximum" + messageSuffix; + ResourceAllocationException e = new ResourceAllocationException(message, type); + s_logger.error(message, e); + throw e; + } + } + domainId = domain.getParent(); + } + } + + private void checkAccountResourceLimit(final Account account, final Project project, final ResourceType type, long numResources) throws ResourceAllocationException { + // Check account limits + long accountResourceLimit = findCorrectResourceLimitForAccount(account, type); + long currentResourceCount = _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); + long requestedResourceCount = currentResourceCount + numResources; + String messageSuffix = " amount of resources of Type = '" + type + "' for " + + (project == null ? "Account Name = " + account.getAccountName() : "Project Name = " + project.getName()) + + " in Domain Id = " + account.getDomainId() + + " is exceeded: Account Resource Limit = " + accountResourceLimit + + ", Current Account Resource Amount = " + currentResourceCount + + ", Requested Resource Amount = " + numResources + "."; + + if(s_logger.isDebugEnabled()) { + s_logger.debug("Checking if" + messageSuffix); + } + + if (accountResourceLimit != Resource.RESOURCE_UNLIMITED && requestedResourceCount > accountResourceLimit) { + String message = "Maximum" + messageSuffix; + ResourceAllocationException e = new ResourceAllocationException(message, type); + s_logger.error(message, e); + throw e; + } + } + + private List lockAccountAndOwnerDomainRows(long accountId, final ResourceType type) { + Set rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(accountId, ResourceOwnerType.Account, type); + SearchCriteria sc = ResourceCountSearch.create(); + sc.setParameters("id", rowIdsToLock.toArray()); + return _resourceCountDao.lockRows(sc, null, true); + } + + private List lockDomainRows(long domainId, final ResourceType type) { + Set rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(domainId, ResourceOwnerType.Domain, type); + SearchCriteria sc = ResourceCountSearch.create(); + sc.setParameters("id", rowIdsToLock.toArray()); + return _resourceCountDao.lockRows(sc, null, true); + } + @Override @DB public void checkResourceLimit(final Account account, final ResourceType type, long... count) throws ResourceAllocationException { @@ -432,51 +505,14 @@ public void checkResourceLimit(final Account account, final ResourceType type, l Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException { - // Lock all rows first so nobody else can read it - Set rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(account.getId(), ResourceOwnerType.Account, type); - SearchCriteria sc = ResourceCountSearch.create(); - sc.setParameters("id", rowIdsToLock.toArray()); - _resourceCountDao.lockRows(sc, null, true); - - // Check account limits - long accountLimit = findCorrectResourceLimitForAccount(account, type); - long potentialCount = _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type) + numResources; - if (accountLimit != Resource.RESOURCE_UNLIMITED && potentialCount > accountLimit) { - String message = - "Maximum number of resources of type '" + type + "' for account name=" + account.getAccountName() + " in domain id=" + account.getDomainId() + - " has been exceeded."; - if (projectFinal != null) { - message = - "Maximum number of resources of type '" + type + "' for project name=" + projectFinal.getName() + " in domain id=" + account.getDomainId() + - " has been exceeded."; - } - ResourceAllocationException e= new ResourceAllocationException(message, type);; - s_logger.error(message, e); - throw e; - } - - // check all domains in the account's domain hierarchy - Long domainId = null; - if (projectFinal != null) { - domainId = projectFinal.getDomainId(); - } else { - domainId = account.getDomainId(); + // Lock all rows first so nobody else can read it + lockAccountAndOwnerDomainRows(account.getId(), type); + // Check account limits + checkAccountResourceLimit(account, projectFinal, type, numResources); + // check all domains in the account's domain hierarchy + checkDomainResourceLimit(account, projectFinal, type, numResources); } - - while (domainId != null) { - DomainVO domain = _domainDao.findById(domainId); - // no limit check if it is ROOT domain - if (domainId != Domain.ROOT_DOMAIN) { - long domainLimit = findCorrectResourceLimitForDomain(domain, type); - long domainCount = _resourceCountDao.getResourceCount(domainId, ResourceOwnerType.Domain, type) + numResources; - if (domainLimit != Resource.RESOURCE_UNLIMITED && domainCount > domainLimit) { - throw new ResourceAllocationException("Maximum number of resources of type '" + type + "' for domain id=" + domainId + " has been exceeded.", type); - } - } - domainId = domain.getParent(); - } - } - }); + }); } @Override @@ -652,7 +688,7 @@ public ResourceLimitVO updateResourceLimit(Long accountId, Long domainId, Intege //Convert max storage size from GiB to bytes if ((resourceType == ResourceType.primary_storage || resourceType == ResourceType.secondary_storage) && max >= 0) { - max = max * ResourceType.bytesToGiB; + max *= ResourceType.bytesToGiB; } ResourceOwnerType ownerType = null; @@ -782,28 +818,25 @@ public List recalculateResourceCount(Long accountId, Long domai @DB protected boolean updateResourceCountForAccount(final long accountId, final ResourceType type, final boolean increment, final long delta) { + if(s_logger.isDebugEnabled()) { + s_logger.debug("Updating resource Type = " + type + " count for Account = " + accountId + + " Operation = " + (increment ? "increasing" : "decreasing") + " Amount = " + delta); + } try { return Transaction.execute(new TransactionCallback() { - @Override - public Boolean doInTransaction(TransactionStatus status) { - boolean result = true; - Set rowsToLock = _resourceCountDao.listAllRowsToUpdate(accountId, ResourceOwnerType.Account, type); - - // Lock rows first - SearchCriteria sc = ResourceCountSearch.create(); - sc.setParameters("id", rowsToLock.toArray()); - List rowsToUpdate = _resourceCountDao.lockRows(sc, null, true); - - for (ResourceCountVO rowToUpdate : rowsToUpdate) { - if (!_resourceCountDao.updateById(rowToUpdate.getId(), increment, delta)) { - s_logger.trace("Unable to update resource count for the row " + rowToUpdate); - result = false; - } - } - - return result; - } - }); + @Override + public Boolean doInTransaction(TransactionStatus status) { + boolean result = true; + List rowsToUpdate = lockAccountAndOwnerDomainRows(accountId, type); + for (ResourceCountVO rowToUpdate : rowsToUpdate) { + if (!_resourceCountDao.updateById(rowToUpdate.getId(), increment, delta)) { + s_logger.trace("Unable to update resource count for the row " + rowToUpdate); + result = false; + } + } + return result; + } + }); } catch (Exception ex) { s_logger.error("Failed to update resource count for account id=" + accountId); return false; @@ -813,113 +846,103 @@ public Boolean doInTransaction(TransactionStatus status) { @DB protected long recalculateDomainResourceCount(final long domainId, final ResourceType type) { return Transaction.execute(new TransactionCallback() { - @Override - public Long doInTransaction(TransactionStatus status) { - long newCount = 0; - - // Lock all rows first so nobody else can read it - Set rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(domainId, ResourceOwnerType.Domain, type); - SearchCriteria sc = ResourceCountSearch.create(); - sc.setParameters("id", rowIdsToLock.toArray()); - _resourceCountDao.lockRows(sc, null, true); + @Override + public Long doInTransaction(TransactionStatus status) { + long newResourceCount = 0; + lockDomainRows(domainId, type); + ResourceCountVO domainRC = _resourceCountDao.findByOwnerAndType(domainId, ResourceOwnerType.Domain, type); + long oldResourceCount = domainRC.getCount(); + + List domainChildren = _domainDao.findImmediateChildrenForParent(domainId); + // for each child domain update the resource count + if (type.supportsOwner(ResourceOwnerType.Domain)) { - ResourceCountVO domainRC = _resourceCountDao.findByOwnerAndType(domainId, ResourceOwnerType.Domain, type); - long oldCount = domainRC.getCount(); + // calculate project count here + if (type == ResourceType.project) { + newResourceCount += _projectDao.countProjectsForDomain(domainId); + } - List domainChildren = _domainDao.findImmediateChildrenForParent(domainId); - // for each child domain update the resource count - if (type.supportsOwner(ResourceOwnerType.Domain)) { + for (DomainVO childDomain : domainChildren) { + long childDomainResourceCount = recalculateDomainResourceCount(childDomain.getId(), type); + newResourceCount += childDomainResourceCount; // add the child domain count to parent domain count + } + } - // calculate project count here - if (type == ResourceType.project) { - newCount = newCount + _projectDao.countProjectsForDomain(domainId); - } + if (type.supportsOwner(ResourceOwnerType.Account)) { + List accounts = _accountDao.findActiveAccountsForDomain(domainId); + for (AccountVO account : accounts) { + long accountResourceCount = recalculateAccountResourceCount(account.getId(), type); + newResourceCount += accountResourceCount; // add account's resource count to parent domain count + } + } + _resourceCountDao.setResourceCount(domainId, ResourceOwnerType.Domain, type, newResourceCount); - for (DomainVO domainChild : domainChildren) { - long domainCount = recalculateDomainResourceCount(domainChild.getId(), type); - newCount = newCount + domainCount; // add the child domain count to parent domain count - } - } + if (oldResourceCount != newResourceCount) { + s_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."); + } - if (type.supportsOwner(ResourceOwnerType.Account)) { - List accounts = _accountDao.findActiveAccountsForDomain(domainId); - for (AccountVO account : accounts) { - long accountCount = recalculateAccountResourceCount(account.getId(), type); - newCount = newCount + accountCount; // add account's resource count to parent domain count + return newResourceCount; } - } - _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."); - } - - return newCount; - } - }); + }); } @DB protected long recalculateAccountResourceCount(final long accountId, final ResourceType type) { Long newCount = Transaction.execute(new TransactionCallback() { - @Override - public Long doInTransaction(TransactionStatus status) { - Long newCount = null; - - // this lock guards against the updates to user_vm, volume, snapshot, public _ip and template table - // as any resource creation precedes with the resourceLimitExceeded check which needs this lock too - Set rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(accountId, Resource.ResourceOwnerType.Account, type); - SearchCriteria sc = ResourceCountSearch.create(); - sc.setParameters("id", rowIdsToLock.toArray()); - _resourceCountDao.lockRows(sc, null, true); - - ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndType(accountId, ResourceOwnerType.Account, type); - long oldCount = 0; - if (accountRC != null) - oldCount = accountRC.getCount(); - - if (type == Resource.ResourceType.user_vm) { - newCount = _userVmDao.countAllocatedVMsForAccount(accountId); - } else if (type == Resource.ResourceType.volume) { - newCount = _volumeDao.countAllocatedVolumesForAccount(accountId); - long virtualRouterCount = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId).size(); - newCount = newCount - virtualRouterCount; // don't count the volumes of virtual router - } else if (type == Resource.ResourceType.snapshot) { - newCount = _snapshotDao.countSnapshotsForAccount(accountId); - } else if (type == Resource.ResourceType.public_ip) { - newCount = calculatePublicIpForAccount(accountId); - } else if (type == Resource.ResourceType.template) { - newCount = _vmTemplateDao.countTemplatesForAccount(accountId); - } else if (type == Resource.ResourceType.project) { - newCount = _projectAccountDao.countByAccountIdAndRole(accountId, Role.Admin); - } else if (type == Resource.ResourceType.network) { - newCount = _networkDao.countNetworksUserCanCreate(accountId); - } else if (type == Resource.ResourceType.vpc) { - newCount = _vpcDao.countByAccountId(accountId); - } else if (type == Resource.ResourceType.cpu) { - newCount = countCpusForAccount(accountId); - } else if (type == Resource.ResourceType.memory) { - newCount = calculateMemoryForAccount(accountId); - } else if (type == Resource.ResourceType.primary_storage) { - List virtualRouters = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId); - newCount = _volumeDao.primaryStorageUsedForAccount(accountId, virtualRouters); - } else if (type == Resource.ResourceType.secondary_storage) { - newCount = calculateSecondaryStorageForAccount(accountId); - } else { - throw new InvalidParameterValueException("Unsupported resource type " + type); - } - _resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (newCount == null) ? 0 : newCount.longValue()); - - // No need to log message for primary and secondary storage because both are recalculating the resource count which will not lead to any discrepancy. - if (!Long.valueOf(oldCount).equals(newCount) && (type != Resource.ResourceType.primary_storage && type != Resource.ResourceType.secondary_storage)) { - 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."); - } + @Override + public Long doInTransaction(TransactionStatus status) { + Long newCount = null; + lockAccountAndOwnerDomainRows(accountId, type); + ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndType(accountId, ResourceOwnerType.Account, type); + long oldCount = 0; + if (accountRC != null) + oldCount = accountRC.getCount(); + + if (type == Resource.ResourceType.user_vm) { + newCount = _userVmDao.countAllocatedVMsForAccount(accountId); + } else if (type == Resource.ResourceType.volume) { + newCount = _volumeDao.countAllocatedVolumesForAccount(accountId); + long virtualRouterCount = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId).size(); + newCount = newCount - virtualRouterCount; // don't count the volumes of virtual router + } else if (type == Resource.ResourceType.snapshot) { + newCount = _snapshotDao.countSnapshotsForAccount(accountId); + } else if (type == Resource.ResourceType.public_ip) { + newCount = calculatePublicIpForAccount(accountId); + } else if (type == Resource.ResourceType.template) { + newCount = _vmTemplateDao.countTemplatesForAccount(accountId); + } else if (type == Resource.ResourceType.project) { + newCount = _projectAccountDao.countByAccountIdAndRole(accountId, Role.Admin); + } else if (type == Resource.ResourceType.network) { + newCount = _networkDao.countNetworksUserCanCreate(accountId); + } else if (type == Resource.ResourceType.vpc) { + newCount = _vpcDao.countByAccountId(accountId); + } else if (type == Resource.ResourceType.cpu) { + newCount = countCpusForAccount(accountId); + } else if (type == Resource.ResourceType.memory) { + newCount = calculateMemoryForAccount(accountId); + } else if (type == Resource.ResourceType.primary_storage) { + List virtualRouters = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId); + newCount = _volumeDao.primaryStorageUsedForAccount(accountId, virtualRouters); + } else if (type == Resource.ResourceType.secondary_storage) { + newCount = calculateSecondaryStorageForAccount(accountId); + } else { + throw new InvalidParameterValueException("Unsupported resource type " + type); + } + _resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (newCount == null) ? 0 : newCount.longValue()); + + // No need to log message for primary and secondary storage because both are recalculating the + // resource count which will not lead to any discrepancy. + if (!Long.valueOf(oldCount).equals(newCount) && + (type != Resource.ResourceType.primary_storage && type != Resource.ResourceType.secondary_storage)) { + s_logger.warn("Discrepency in the resource count " + "(original count=" + oldCount + " correct count = " + newCount + ") for type " + type + + " for account ID " + accountId + " is fixed during resource count recalculation."); + } - return newCount; - } - }); + return newCount; + } + }); return (newCount == null) ? 0 : newCount.longValue(); } @@ -1081,7 +1104,7 @@ public ResourceCountCheckTask() { @Override protected void runInContext() { - s_logger.info("Running resource count check periodic task"); + s_logger.info("Started resource counters recalculation periodic task."); List domains = _domainDao.findImmediateChildrenForParent(Domain.ROOT_DOMAIN); // recalculateDomainResourceCount will take care of re-calculation of resource counts for sub-domains diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 37b72a68d145..224fa78370f1 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -816,7 +816,7 @@ public VolumeVO createVolume(CreateVolumeCmd cmd) { if (!created) { s_logger.trace("Decrementing volume resource count for account id=" + volume.getAccountId() + " as volume failed to create on the backend"); _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, cmd.getDisplayVolume()); - _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), ResourceType.primary_storage.getOrdinal()); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, cmd.getDisplayVolume(), new Long(volume.getSize())); } } } @@ -1262,6 +1262,7 @@ public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOper if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) { // Decrement the resource count for volumes and primary storage belonging user VM's only _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplayVolume()); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplayVolume(), new Long(volume.getSize())); } } // Mark volume as removed if volume has not been created on primary or secondary @@ -1277,7 +1278,8 @@ public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOper AsyncCallFuture future = volService.expungeVolumeAsync(volOnPrimary); future.get(); //decrement primary storage count - _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), ResourceType.primary_storage.getOrdinal()); + _resourceLimitMgr.decrementResourceCount(volOnPrimary.getAccountId(), ResourceType.volume, volOnPrimary.isDisplayVolume()); + _resourceLimitMgr.decrementResourceCount(volOnPrimary.getAccountId(), ResourceType.primary_storage, volOnPrimary.isDisplayVolume(), new Long(volOnPrimary.getSize())); } // expunge volume from secondary if volume is on image store VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image); @@ -1286,7 +1288,7 @@ public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOper AsyncCallFuture future2 = volService.expungeVolumeAsync(volOnSecondary); future2.get(); //decrement secondary storage count - _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), ResourceType.secondary_storage.getOrdinal()); + _resourceLimitMgr.decrementResourceCount(volOnSecondary.getAccountId(), ResourceType.secondary_storage, new Long(volOnSecondary.getSize())); } // delete all cache entries for this volume List cacheVols = volFactory.listVolumeOnCache(volume.getId()); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index f074c332e3ca..05b304733756 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -305,8 +305,7 @@ public Snapshot revertSnapshot(Long snapshotId) { boolean result = snapshotStrategy.revertSnapshot(snapshotInfo); if (result) { // update volume size and primary storage count - _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, - new Long(volume.getSize() - snapshot.getSize())); + _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize() - snapshot.getSize())); volume.setSize(snapshot.getSize()); _volsDao.update(volume.getId(), volume); return snapshotInfo; diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 3591e603b0aa..bdcb3c0c038f 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2130,7 +2130,7 @@ public boolean expunge(UserVmVO vm, long callerUserId, Account caller) { // Update Resource count if (vm.getAccountId() != Account.ACCOUNT_ID_SYSTEM && !rootVol.isEmpty()) { _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), ResourceType.volume); - _resourceLimitMgr.recalculateResourceCount(vm.getAccountId(), vm.getDomainId(), ResourceType.primary_storage.getOrdinal()); + _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, new Long(rootVol.get(0).getSize())); } // Only if vm is not expunged already, cleanup it's resources @@ -5479,51 +5479,48 @@ public UserVm moveVMToUser(final AssignVMCmd cmd) throws ResourceAllocationExcep Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - //generate destroy vm event for usage - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), - vm.getTemplateId(), vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); - - // update resource counts for old account + //generate destroy vm event for usage + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), + vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), + vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); + // update resource counts for old account resourceCountDecrement(oldAccount.getAccountId(), vm.isDisplayVm(), new Long(offering.getCpu()), new Long(offering.getRamSize())); - // OWNERSHIP STEP 1: update the vm owner - vm.setAccountId(newAccount.getAccountId()); - vm.setDomainId(cmd.getDomainId()); - _vmDao.persist(vm); + // OWNERSHIP STEP 1: update the vm owner + vm.setAccountId(newAccount.getAccountId()); + vm.setDomainId(cmd.getDomainId()); + _vmDao.persist(vm); - // OS 2: update volume - for (VolumeVO volume : volumes) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), - Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); - _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.volume); - _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); - volume.setAccountId(newAccount.getAccountId()); - volume.setDomainId(newAccount.getDomainId()); - _volsDao.persist(volume); - _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume); - _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), - volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); - //snapshots: mark these removed in db - List snapshots = _snapshotDao.listByVolumeIdIncludingRemoved(volume.getId()); - for (SnapshotVO snapshot : snapshots) { - boolean result = _snapshotService.deleteSnapshot(snapshot.getId()); - if (result) { - s_logger.info("Snapshot id: " + snapshot.getId() + " delete successfully "); - } else { - s_logger.error("Unable to delete Snapshot id: " + snapshot.getId()); + // OS 2: update volume + for (VolumeVO volume : volumes) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), + volume.getId(), volume.getName(), Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); + _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.volume); + _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); + volume.setAccountId(newAccount.getAccountId()); + volume.setDomainId(newAccount.getDomainId()); + _volsDao.persist(volume); + _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume); + _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), + volume.getName(), volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), + Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); + //snapshots: mark these removed in db + List snapshots = _snapshotDao.listByVolumeIdIncludingRemoved(volume.getId()); + for (SnapshotVO snapshot : snapshots) { + _snapshotDao.remove(snapshot.getId()); } - } - } + } - //update resource count of new account + //update resource count of new account resourceCountIncrement(newAccount.getAccountId(), vm.isDisplayVm(), new Long(offering.getCpu()), new Long(offering.getRamSize())); - //generate usage events to account for this change - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), - vm.getTemplateId(), vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); + //generate usage events to account for this change + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), + vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), + VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); } - }); + }); VirtualMachine vmoi = _itMgr.findById(vm.getId()); VirtualMachineProfileImpl vmOldProfile = new VirtualMachineProfileImpl(vmoi);