Skip to content

Commit 0f94fab

Browse files
committed
Refactor Quota balance
1 parent 4f93ba8 commit 0f94fab

File tree

15 files changed

+411
-536
lines changed

15 files changed

+411
-536
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ public class ApiConstants {
6969
public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved";
7070
public static final String IS_BACKUP_VM_EXPUNGED = "isbackupvmexpunged";
7171
public static final String BACKUP_TOTAL = "backuptotal";
72+
public static final String BALANCE = "balance";
73+
public static final String BALANCES = "balances";
7274
public static final String BASE64_IMAGE = "base64image";
7375
public static final String BGP_PEERS = "bgppeers";
7476
public static final String BGP_PEER_IDS = "bgppeerids";
@@ -157,6 +159,7 @@ public class ApiConstants {
157159
public static final String CUSTOM_ID = "customid";
158160
public static final String CUSTOM_ACTION_ID = "customactionid";
159161
public static final String CUSTOM_JOB_ID = "customjobid";
162+
public static final String CURRENCY = "currency";
160163
public static final String CURRENT_START_IP = "currentstartip";
161164
public static final String CURRENT_END_IP = "currentendip";
162165
public static final String ENCRYPT = "encrypt";
@@ -170,6 +173,7 @@ public class ApiConstants {
170173
public static final String DATACENTER_NAME = "datacentername";
171174
public static final String DATADISKS_DETAILS = "datadisksdetails";
172175
public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist";
176+
public static final String DATE = "date";
173177
public static final String DEFAULT_VALUE = "defaultvalue";
174178
public static final String DELETE_PROTECTION = "deleteprotection";
175179
public static final String DESCRIPTION = "description";

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,9 @@ protected void processQuotaBalanceForAccount(AccountVO accountVo, List<QuotaUsag
150150
return;
151151
}
152152

153-
Date startDate = accountQuotaUsages.get(0).getStartDate();
154-
Date endDate = accountQuotaUsages.get(0).getEndDate();
153+
QuotaUsageVO firstQuotaUsage = accountQuotaUsages.get(0);
154+
Date startDate = firstQuotaUsage.getStartDate();
155+
Date endDate = firstQuotaUsage.getEndDate();
155156
Date lastQuotaUsageEndDate = accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate();
156157

157158
LinkedHashSet<Pair<Date, Date>> periods = accountQuotaUsages.stream()
@@ -215,7 +216,7 @@ protected BigDecimal retrieveBalanceForUsageCalculation(long accountId, long dom
215216
logger.debug(String.format("Persisting the first quota balance [%s] for account [%s].", firstBalance, accountToString));
216217
_quotaBalanceDao.saveQuotaBalance(firstBalance);
217218
} else {
218-
QuotaBalanceVO lastRealBalance = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, startDate);
219+
QuotaBalanceVO lastRealBalance = _quotaBalanceDao.getLastQuotaBalanceEntry(accountId, domainId, startDate);
219220

220221
if (lastRealBalance == null) {
221222
logger.warn("Account [{}] has quota usage entries, however it does not have a quota balance.", accountToString);
@@ -244,7 +245,7 @@ protected void saveQuotaAccount(long accountId, BigDecimal aggregatedUsage, Date
244245
}
245246

246247
protected BigDecimal aggregateCreditBetweenDates(Long accountId, Long domainId, Date startDate, Date endDate, String accountToString) {
247-
List<QuotaBalanceVO> creditsReceived = _quotaBalanceDao.findCreditBalance(accountId, domainId, startDate, endDate);
248+
List<QuotaBalanceVO> creditsReceived = _quotaBalanceDao.findCreditBalances(accountId, domainId, startDate, endDate);
248249
logger.debug("Account [{}] has [{}] credit entries before [{}].", accountToString, creditsReceived.size(),
249250
DateUtil.displayDateInTimezone(usageAggregationTimeZone, endDate));
250251

framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,13 @@ public interface QuotaBalanceDao extends GenericDao<QuotaBalanceVO, Long> {
2828

2929
QuotaBalanceVO saveQuotaBalance(QuotaBalanceVO qb);
3030

31-
List<QuotaBalanceVO> findCreditBalance(Long accountId, Long domainId, Date startDate, Date endDate);
31+
List<QuotaBalanceVO> findCreditBalances(Long accountId, Long domainId, Date startDate, Date endDate);
3232

33-
QuotaBalanceVO findLastBalanceEntry(Long accountId, Long domainId, Date beforeThis);
33+
QuotaBalanceVO getLastQuotaBalanceEntry(Long accountId, Long domainId, Date beforeThis);
3434

3535
QuotaBalanceVO findLaterBalanceEntry(Long accountId, Long domainId, Date afterThis);
3636

37-
List<QuotaBalanceVO> findQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate);
38-
39-
List<QuotaBalanceVO> lastQuotaBalanceVO(Long accountId, Long domainId, Date startDate);
40-
41-
BigDecimal lastQuotaBalance(Long accountId, Long domainId, Date startDate);
37+
List<QuotaBalanceVO> listQuotaBalances(Long accountId, Long domainId, Date startDate, Date endDate);
38+
BigDecimal getLastQuotaBalance(Long accountId, Long domainId);
4239

4340
}

framework/quota/src/main/java/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java

Lines changed: 67 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import java.math.BigDecimal;
2020
import java.util.ArrayList;
21-
import java.util.Collections;
2221
import java.util.Date;
2322
import java.util.List;
2423

2524
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
25+
import org.apache.commons.lang3.ObjectUtils;
26+
import org.apache.commons.lang3.time.DateUtils;
27+
import org.apache.logging.log4j.LogManager;
28+
import org.apache.logging.log4j.Logger;
2629
import org.springframework.stereotype.Component;
2730

2831
import com.cloud.utils.db.Filter;
@@ -32,160 +35,104 @@
3235
import com.cloud.utils.db.Transaction;
3336
import com.cloud.utils.db.TransactionCallback;
3437
import com.cloud.utils.db.TransactionLegacy;
35-
import com.cloud.utils.db.TransactionStatus;
3638

3739
@Component
3840
public class QuotaBalanceDaoImpl extends GenericDaoBase<QuotaBalanceVO, Long> implements QuotaBalanceDao {
41+
private static final Logger logger = LogManager.getLogger(QuotaBalanceDaoImpl.class);
3942

4043
@Override
41-
public QuotaBalanceVO findLastBalanceEntry(final Long accountId, final Long domainId, final Date beforeThis) {
42-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
43-
@Override
44-
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
45-
List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
46-
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L);
47-
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
48-
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
49-
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
50-
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
44+
public QuotaBalanceVO getLastQuotaBalanceEntry(final Long accountId, final Long domainId, final Date beforeThis) {
45+
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<QuotaBalanceVO>) status -> {
46+
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L);
47+
QueryBuilder<QuotaBalanceVO> qb = getQuotaBalanceQueryBuilder(accountId, domainId);
48+
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
49+
50+
if (beforeThis != null) {
5151
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LT, beforeThis);
52-
quotaBalanceEntries = search(qb.create(), filter);
53-
return !quotaBalanceEntries.isEmpty() ? quotaBalanceEntries.get(0) : null;
5452
}
53+
54+
List<QuotaBalanceVO> quotaBalanceEntries = search(qb.create(), filter);
55+
return !quotaBalanceEntries.isEmpty() ? quotaBalanceEntries.get(0) : null;
5556
});
5657
}
5758

5859
@Override
5960
public QuotaBalanceVO findLaterBalanceEntry(final Long accountId, final Long domainId, final Date afterThis) {
60-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
61-
@Override
62-
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
63-
List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
64-
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L);
65-
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
66-
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
67-
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
68-
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
69-
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.GT, afterThis);
70-
quotaBalanceEntries = search(qb.create(), filter);
71-
return quotaBalanceEntries.size() > 0 ? quotaBalanceEntries.get(0) : null;
72-
}
61+
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<QuotaBalanceVO>) status -> {
62+
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L);
63+
QueryBuilder<QuotaBalanceVO> qb = getQuotaBalanceQueryBuilder(accountId, domainId);
64+
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
65+
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.GT, afterThis);
66+
67+
List<QuotaBalanceVO> quotaBalanceEntries = search(qb.create(), filter);
68+
return !quotaBalanceEntries.isEmpty() ? quotaBalanceEntries.get(0) : null;
7369
});
7470
}
7571

7672
@Override
7773
public QuotaBalanceVO saveQuotaBalance(final QuotaBalanceVO qb) {
78-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
79-
@Override
80-
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
81-
return persist(qb);
82-
}
83-
});
74+
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<QuotaBalanceVO>) status -> persist(qb));
8475
}
8576

8677
@Override
87-
public List<QuotaBalanceVO> findCreditBalance(final Long accountId, final Long domainId, final Date lastbalancedate, final Date beforeThis) {
88-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
89-
@Override
90-
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
91-
if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) {
92-
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
93-
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
94-
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
95-
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
96-
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.GT, 0);
97-
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis);
98-
return search(qb.create(), filter);
99-
} else {
100-
return new ArrayList<QuotaBalanceVO>();
101-
}
78+
public List<QuotaBalanceVO> findCreditBalances(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
79+
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<List<QuotaBalanceVO>>) status -> {
80+
if (ObjectUtils.anyNull(startDate, endDate) || startDate.after(endDate)) {
81+
return new ArrayList<>();
10282
}
103-
});
104-
}
10583

106-
@Override
107-
public List<QuotaBalanceVO> findQuotaBalance(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
108-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
109-
@Override
110-
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
111-
List<QuotaBalanceVO> quotaUsageRecords = null;
112-
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
113-
if (accountId != null) {
114-
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
115-
}
116-
if (domainId != null) {
117-
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
118-
}
119-
if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
120-
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
121-
} else {
122-
return Collections.<QuotaBalanceVO> emptyList();
123-
}
124-
quotaUsageRecords = listBy(qb.create());
125-
if (quotaUsageRecords.size() == 0) {
126-
quotaUsageRecords.addAll(lastQuotaBalanceVO(accountId, domainId, startDate));
127-
}
128-
return quotaUsageRecords;
84+
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
85+
QueryBuilder<QuotaBalanceVO> qb = getQuotaBalanceQueryBuilder(accountId, domainId);
86+
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.GT, 0);
87+
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
12988

130-
}
89+
return search(qb.create(), filter);
13190
});
132-
13391
}
13492

13593
@Override
136-
public List<QuotaBalanceVO> lastQuotaBalanceVO(final Long accountId, final Long domainId, final Date pivotDate) {
137-
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
138-
@Override
139-
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
140-
List<QuotaBalanceVO> quotaUsageRecords = null;
141-
List<QuotaBalanceVO> trimmedRecords = new ArrayList<QuotaBalanceVO>();
142-
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L);
143-
// ASSUMPTION there will be less than 100 continuous credit
144-
// transactions
145-
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
146-
if (accountId != null) {
147-
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
148-
}
149-
if (domainId != null) {
150-
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
151-
}
152-
if ((pivotDate != null)) {
153-
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LTEQ, pivotDate);
154-
}
155-
quotaUsageRecords = search(qb.create(), filter);
156-
157-
// get records before startDate to find start balance
158-
for (QuotaBalanceVO entry : quotaUsageRecords) {
159-
if (logger.isDebugEnabled()) {
160-
logger.debug("FindQuotaBalance Entry=" + entry);
161-
}
162-
if (entry.getCreditsId() > 0) {
163-
trimmedRecords.add(entry);
164-
} else {
165-
trimmedRecords.add(entry);
166-
break; // add only consecutive credit entries and last balance entry
167-
}
168-
}
169-
return trimmedRecords;
94+
public List<QuotaBalanceVO> listQuotaBalances(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
95+
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<List<QuotaBalanceVO>>) status -> {
96+
QueryBuilder<QuotaBalanceVO> qb = getQuotaBalanceQueryBuilder(accountId, domainId);
97+
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
98+
if (startDate != null) {
99+
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.GTEQ, startDate);
100+
}
101+
if (endDate != null) {
102+
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LTEQ, endDate);
170103
}
104+
105+
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true);
106+
return listBy(qb.create(), filter);
171107
});
172108
}
173109

174110
@Override
175-
public BigDecimal lastQuotaBalance(final Long accountId, final Long domainId, Date startDate) {
176-
List<QuotaBalanceVO> quotaBalance = lastQuotaBalanceVO(accountId, domainId, startDate);
177-
BigDecimal finalBalance = new BigDecimal(0);
178-
if (quotaBalance.isEmpty()) {
179-
logger.info("There are no balance entries on or before the requested date.");
180-
return finalBalance;
111+
public BigDecimal getLastQuotaBalance(final Long accountId, final Long domainId) {
112+
QuotaBalanceVO quotaBalance = getLastQuotaBalanceEntry(accountId, domainId, null);
113+
BigDecimal finalBalance = BigDecimal.ZERO;
114+
Date startDate = DateUtils.addDays(new Date(), -1);
115+
if (quotaBalance == null) {
116+
logger.info("There are no balance entries for account [{}] and domain [{}]. Considering only new added credits.", accountId, domainId);
117+
} else {
118+
finalBalance = quotaBalance.getCreditBalance();
119+
startDate = quotaBalance.getUpdatedOn();
181120
}
182-
for (QuotaBalanceVO entry : quotaBalance) {
183-
if (logger.isDebugEnabled()) {
184-
logger.debug("lastQuotaBalance Entry=" + entry);
185-
}
186-
finalBalance = finalBalance.add(entry.getCreditBalance());
121+
122+
List<QuotaBalanceVO> credits = findCreditBalances(accountId, domainId, startDate, new Date());
123+
124+
for (QuotaBalanceVO credit : credits) {
125+
finalBalance = finalBalance.add(credit.getCreditBalance());
187126
}
127+
188128
return finalBalance;
189129
}
190130

131+
private QueryBuilder<QuotaBalanceVO> getQuotaBalanceQueryBuilder(Long accountId, Long domainId) {
132+
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
133+
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
134+
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
135+
return qb;
136+
}
137+
191138
}

0 commit comments

Comments
 (0)