Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public interface UsageDao extends GenericDao<UsageVO, Long> {

void saveUsageRecords(List<UsageVO> usageRecords);

void removeOldUsageRecords(int days);
void expungeAllOlderThan(int days, long limitPerQuery);

UsageVO persistUsage(final UsageVO usage);

Expand Down
37 changes: 20 additions & 17 deletions engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;

import org.apache.cloudstack.acl.RoleType;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Component;

import java.sql.PreparedStatement;
Expand All @@ -51,7 +52,6 @@
public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements UsageDao {
private static final String DELETE_ALL = "DELETE FROM cloud_usage";
private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?";
private static final String DELETE_ALL_BY_INTERVAL = "DELETE FROM cloud_usage WHERE end_date < DATE_SUB(CURRENT_DATE(), INTERVAL ? DAY)";
private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, uuid, type, role_id, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?,?,?)";
private static final String INSERT_USER_STATS = "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received,"
+ " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
Expand Down Expand Up @@ -88,8 +88,12 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage

private static final String UPDATE_BUCKET_STATS = "UPDATE cloud_usage.bucket_statistics SET size=? WHERE id=?";

protected SearchBuilder<UsageVO> endDateLessThanSearch;

public UsageDaoImpl() {
endDateLessThanSearch = createSearchBuilder();
endDateLessThanSearch.and("endDate", endDateLessThanSearch.entity().getEndDate(), SearchCriteria.Op.LT);
endDateLessThanSearch.done();
}

@Override
Expand Down Expand Up @@ -539,21 +543,20 @@ public void saveUsageRecords(List<UsageVO> usageRecords) {
}

@Override
public void removeOldUsageRecords(int days) {
Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmt = null;
try {
pstmt = txn.prepareAutoCloseStatement(DELETE_ALL_BY_INTERVAL);
pstmt.setLong(1, days);
pstmt.executeUpdate();
} catch (Exception ex) {
logger.error("error removing old cloud_usage records for interval: " + days);
}
}
});
public void expungeAllOlderThan(int days, long limitPerQuery) {
SearchCriteria<UsageVO> sc = endDateLessThanSearch.create();

Date limit = DateUtils.addDays(new Date(), -days);
sc.setParameters("endDate", limit);

TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
try {
logger.debug("Removing all cloud_usage records older than [{}].", limit);
int totalExpunged = batchExpunge(sc, limitPerQuery);
logger.info("Removed a total of [{}] cloud_usage records older than [{}].", totalExpunged, limit);
} finally {
txn.close();
}
}

public UsageVO persistUsage(final UsageVO usage) {
Expand Down
3 changes: 2 additions & 1 deletion framework/db/src/main/java/com/cloud/utils/db/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public Filter(Class<?> clazz, String field, boolean ascending) {
}

public Filter(long limit) {
_orderBy = " ORDER BY RAND() LIMIT " + limit;
_orderBy = " ORDER BY RAND()";
_limit = limit;
}

public Filter(Long offset, Long limit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,8 @@ protected void addFilter(final StringBuilder sql, final Filter filter) {
if (filter.getLimit() != null) {
sql.append(", ").append(filter.getLimit());
}
} else if (filter.getLimit() != null) {
sql.append(" LIMIT ").append(filter.getLimit());
}
}
}
Expand Down Expand Up @@ -1322,7 +1324,7 @@ public int batchExpunge(final SearchCriteria<T> sc, final Long batchSize) {
Filter filter = null;
final long batchSizeFinal = ObjectUtils.defaultIfNull(batchSize, 0L);
if (batchSizeFinal > 0) {
filter = new Filter(batchSizeFinal);
filter = new Filter(null, batchSizeFinal);
}
int expunged = 0;
int currentExpunged = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
public static final ConfigKey<Long> DELETE_QUERY_BATCH_SIZE = new ConfigKey<>("Advanced", Long.class, "delete.query.batch.size", "0",
"Indicates the limit applied while deleting entries in bulk. With this, the delete query will apply the limit as many times as necessary," +
" to delete all the entries. This is advised when retaining several days of records, which can lead to slowness. <= 0 means that no limit will " +
"be applied. Default value is 0. For now, this is used for deletion of vm & volume stats only.", true);
"be applied. Default value is 0. For now, this is used for deletion of VM stats, volume stats, and usage records.", true);
Comment on lines 527 to +530
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we make the default some biug value to protect the operator from trying to delete 500000+ records? (i am thinking about 10000)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it would be good to enable batch deletion by default. 10,000 is too low and might end up slowing down deletion too much though. I've seen vm_stats with over 100 million entries for deletion, which would take too long with batches of 10,000. I will check how some different values behave later.

By the way, I'm putting this in draft because I noticed an issue in the code.


private static final String IOPS_READ_RATE = "IOPS Read";
private static final String IOPS_WRITE_RATE = "IOPS Write";
Expand Down
3 changes: 2 additions & 1 deletion server/src/main/java/com/cloud/usage/UsageServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.cloud.configuration.ConfigurationManagerImpl;
import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd;
import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd;
import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd;
Expand Down Expand Up @@ -489,7 +490,7 @@ public boolean removeRawUsageRecords(RemoveRawUsageRecordsCmd cmd) throws Invali
}
}
}
_usageDao.removeOldUsageRecords(interval);
_usageDao.expungeAllOlderThan(interval, ConfigurationManagerImpl.DELETE_QUERY_BATCH_SIZE.value());
} else {
throw new InvalidParameterValueException("Invalid interval value. Interval to remove cloud_usage records should be greater than 0");
}
Expand Down
Loading