From 6688220cb2b4c0e68088ca64bcbbcd5e72c325eb Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Tue, 21 Jul 2015 14:11:04 +0530 Subject: [PATCH] quota: fixed transaction, boundary conditions --- .../api/command/QuotaBalanceCmd.java | 7 +-- .../apache/cloudstack/quota/QuotaDBUtils.java | 4 +- .../cloudstack/quota/QuotaDBUtilsImpl.java | 10 ++-- .../cloudstack/quota/QuotaManagerImpl.java | 52 ++++++++++--------- .../cloudstack/quota/QuotaServiceImpl.java | 22 ++++++-- .../quota/dao/QuotaBalanceDaoImpl.java | 35 ++++++++++++- .../quota/dao/QuotaTariffDaoImpl.java | 16 +++--- 7 files changed, 98 insertions(+), 48 deletions(-) diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java index ca19b24e86d..bafe0a7b71e 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java @@ -128,13 +128,10 @@ public class QuotaBalanceCmd extends BaseCmd { QuotaBalanceResponse response; if (getEndDate() == null) { - response = _quotaDBUtils.createQuotaLastBalanceResponse(quotaUsage); + response = _quotaDBUtils.createQuotaLastBalanceResponse(quotaUsage, startDate); } else { - response = _quotaDBUtils.createQuotaBalanceResponse(quotaUsage); - response.setEndDate(endDate); + response = _quotaDBUtils.createQuotaBalanceResponse(quotaUsage, startDate, endDate); } - response.setStartDate(startDate); - response.setResponseName(getCommandName()); setResponseObject(response); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java index 0c93e7b946e..02e95fb74a8 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java @@ -40,13 +40,13 @@ public interface QuotaDBUtils { QuotaStatementResponse createQuotaStatementResponse(List quotaUsage); - QuotaBalanceResponse createQuotaBalanceResponse(List quotaUsage); + QuotaBalanceResponse createQuotaBalanceResponse(List quotaUsage, Date startDate, Date endDate); Pair, Integer> getUsageRecords(long accountId, long domainId); ServiceOfferingVO findServiceOffering(Long vmId, long serviceOfferingId); - QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance); + QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance, Date startDate); QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Date despositedOn); diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java index 3401f545f6f..6aade306550 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java @@ -83,7 +83,7 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { } @Override - public QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance) { + public QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance, Date startDate) { if (quotaBalance.size() == 0) { new InvalidParameterValueException("There are no balance entries on or before the requested date."); } @@ -101,17 +101,17 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { lastCredits=lastCredits.add(entry.getCreditBalance()); } else { - resp.setStartDate(entry.getUpdatedOn()); resp.setStartQuota(entry.getCreditBalance().add(lastCredits)); break; // add only consecutive credit entries } } + resp.setStartDate(startDate); resp.setObjectName("balance"); return resp; } @Override - public QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance) { + public QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance, Date startDate, Date endDate) { if (quotaBalance.size() == 0) { new InvalidParameterValueException("The request period does not contain balance entries."); } @@ -133,9 +133,9 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { if (quotaBalance.size() > 0) { QuotaBalanceVO startItem = quotaBalance.get(0); QuotaBalanceVO endItem = quotaBalance.get(quotaBalance.size() - 1); - resp.setStartDate(startItem.getUpdatedOn()); + resp.setStartDate(startDate); resp.setStartQuota(startItem.getCreditBalance()); - resp.setEndDate(endItem.getUpdatedOn()); + resp.setEndDate(endDate); resp.setEndQuota(endItem.getCreditBalance()); } else { resp.setStartQuota(new BigDecimal(0)); diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index 4d0e6a528a0..af34989f899 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -154,34 +154,36 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { } while ((usageRecords != null) && !usageRecords.first().isEmpty()); // list of quotas for this account s_logger.info("Quota entries size = " + quotalistforaccount.size()); - quotalistforaccount.add(new QuotaUsageVO()); - Date startDate = new Date(0); - Date endDate = new Date(0); - BigDecimal aggrUsage = new BigDecimal(0); - for (QuotaUsageVO entry : quotalistforaccount) { - if (startDate.compareTo(entry.getStartDate()) != 0) { - QuotaBalanceVO lastrealbalanceentry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), startDate); - Date lastbalancedate; - if (lastrealbalanceentry != null) { - lastbalancedate = lastrealbalanceentry.getUpdatedOn(); - aggrUsage = aggrUsage.add(lastrealbalanceentry.getCreditBalance()); - } else { - lastbalancedate = new Date(0); - } + if (quotalistforaccount.size() > 0) { // balance to be processed + quotalistforaccount.add(new QuotaUsageVO()); + Date startDate = new Date(0); + Date endDate = new Date(0); + BigDecimal aggrUsage = new BigDecimal(0); + for (QuotaUsageVO entry : quotalistforaccount) { + if (startDate.compareTo(entry.getStartDate()) != 0) { + QuotaBalanceVO lastrealbalanceentry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), startDate); + Date lastbalancedate; + if (lastrealbalanceentry != null) { + lastbalancedate = lastrealbalanceentry.getUpdatedOn(); + aggrUsage = aggrUsage.add(lastrealbalanceentry.getCreditBalance()); + } else { + lastbalancedate = new Date(0); + } - List creditsrcvd = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), lastbalancedate, endDate); - for (QuotaBalanceVO credit : creditsrcvd) { - aggrUsage = aggrUsage.add(credit.getCreditBalance()); - } + List creditsrcvd = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), lastbalancedate, endDate); + for (QuotaBalanceVO credit : creditsrcvd) { + aggrUsage = aggrUsage.add(credit.getCreditBalance()); + } - QuotaBalanceVO newbalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate); - _quotaBalanceDao.persist(newbalance); - aggrUsage = new BigDecimal(0); + QuotaBalanceVO newbalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate); + _quotaBalanceDao.persist(newbalance); + aggrUsage = new BigDecimal(0); + } + startDate = entry.getStartDate(); + endDate = entry.getEndDate(); + aggrUsage = aggrUsage.subtract(entry.getQuotaUsed()); } - startDate = entry.getStartDate(); - endDate = entry.getEndDate(); - aggrUsage = aggrUsage.subtract(entry.getQuotaUsed()); - } + }// balance processed } // END ACCOUNT jobResult = true; } catch (Exception e) { diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java index 567779196fc..0e2e1ac2f6c 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java @@ -168,12 +168,26 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi Date adjustedStartDate = computeAdjustedTime(startDate, usageTZ); if (endDate == null) { - s_logger.debug("getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", on or before " + adjustedStartDate); - return _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate); + s_logger.debug("Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", on or before " + adjustedStartDate); + List qbrecords = _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate); + s_logger.info("Found records size=" + qbrecords.size()); + if (qbrecords.size() == 0){ + throw new InvalidParameterValueException("Incorrect Date there are no quota records before this date " + adjustedStartDate); + } + else { + return qbrecords; + } } else if (startDate.before(endDate)) { Date adjustedEndDate = computeAdjustedTime(endDate, usageTZ); - s_logger.debug("getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate); - return _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate); + s_logger.debug("Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate); + List qbrecords = _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate); + s_logger.info("Found records size=" + qbrecords.size()); + if (qbrecords.size() == 0){ + throw new InvalidParameterValueException("Incorrect Date range there are no quota records between these dates start date " + adjustedStartDate + " and end date:" + endDate); + } + else { + return qbrecords; + } } else { throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index 1e970b415c6..b0ee3b6c3fb 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -18,12 +18,14 @@ package org.apache.cloudstack.quota.dao; import java.util.ArrayList; import java.util.Date; +import java.util.Iterator; import java.util.List; import javax.ejb.Local; import org.springframework.stereotype.Component; import org.apache.cloudstack.quota.QuotaBalanceVO; +import org.apache.log4j.Logger; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -33,6 +35,7 @@ import com.cloud.utils.db.TransactionLegacy; @Component @Local(value = { QuotaBalanceDao.class }) public class QuotaBalanceDaoImpl extends GenericDaoBase implements QuotaBalanceDao { + private static final Logger s_logger = Logger.getLogger(QuotaBalanceDaoImpl.class.getName()); @SuppressWarnings("deprecation") @Override @@ -121,6 +124,21 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im return new ArrayList(); } quotaUsageRecords = listBy(sc); + + // get records before startDate to find start balance + List quotaUsageOnOrBeforeStartDate = findQuotaBalance(accountId, domainId, startDate); + for (Iterator it = quotaUsageOnOrBeforeStartDate.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + if (entry.getCreditsId() > 0) { + quotaUsageRecords.add(entry); + } else { + quotaUsageRecords.add(entry); + break; // add only consecutive credit entries and last + // balance entry + } + } + } finally { txn.close(); } @@ -136,6 +154,7 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); List quotaUsageRecords = null; + List trimmedRecords = new ArrayList(); try { Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L); // ASSUMPTION there will be less than 100 continuous credit @@ -151,12 +170,26 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im sc.addAnd("updatedOn", SearchCriteria.Op.LTEQ, startDate); } quotaUsageRecords = search(sc, filter); + + // get records before startDate to find start balance + for (Iterator it = quotaUsageRecords.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + if (entry.getCreditsId() > 0) { + trimmedRecords.add(entry); + } else { + trimmedRecords.add(entry); + break; // add only consecutive credit entries and last + // balance entry + } + } + } finally { txn.close(); } TransactionLegacy.open(opendb).close(); - return quotaUsageRecords; + return trimmedRecords; } } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java index 88a46afae23..6a95d451ded 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java @@ -45,6 +45,7 @@ public class QuotaTariffDaoImpl extends GenericDaoBase impl @Override public QuotaTariffVO findTariffPlanByUsageType(final int usageType) { + short opendb = TransactionLegacy.currentTxn().getDatabaseId(); QuotaTariffVO result = null; TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); try { @@ -53,14 +54,15 @@ public class QuotaTariffDaoImpl extends GenericDaoBase impl result = findOneBy(sc); } finally { txn.close(); - // Switch back to Cloud DB - TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + // Switch back + TransactionLegacy.open(opendb).close(); } return result; } @Override public List listAllTariffPlans() { + short opendb = TransactionLegacy.currentTxn().getDatabaseId(); List result = null; TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); try { @@ -69,17 +71,19 @@ public class QuotaTariffDaoImpl extends GenericDaoBase impl result = listBy(sc); } finally { txn.close(); - // Switch back to Cloud DB - TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + // Switch back + TransactionLegacy.open(opendb).close(); } return result; } @Override public boolean updateQuotaTariff(QuotaTariffVO plan) { - TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); // Switch to Usage DB + short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); // Switch to + // Usage DB boolean result = this.update(plan.getId(), plan); - TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); // Switch back to Cloud DB + TransactionLegacy.open(opendb).close(); // Switch back return result; } }