This is an automated email from the ASF dual-hosted git repository.

bstoyanov pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.20 by this push:
     new b7fc7179fca Add batch deletion support to `removeRawUsageRecords` 
(#12522)
b7fc7179fca is described below

commit b7fc7179fca83f12f2b6ef4d215b02f79f04bcba
Author: Fabricio Duarte <[email protected]>
AuthorDate: Thu Jan 29 03:14:05 2026 -0300

    Add batch deletion support to `removeRawUsageRecords` (#12522)
    
    * Add batch deletion support to `removeRawUsageRecords`
    
    * Remove ORDER BY from batch expunge
---
 .../main/java/com/cloud/usage/dao/UsageDao.java    |  2 +-
 .../java/com/cloud/usage/dao/UsageDaoImpl.java     | 37 ++++++++++++----------
 .../src/main/java/com/cloud/utils/db/Filter.java   |  3 +-
 .../java/com/cloud/utils/db/GenericDaoBase.java    |  4 ++-
 .../configuration/ConfigurationManagerImpl.java    |  2 +-
 .../java/com/cloud/usage/UsageServiceImpl.java     |  3 +-
 6 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java 
b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
index ea490e60f9e..b9d8d9c0536 100644
--- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
@@ -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);
 
diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
index 34e7843bfc4..2d99c78fad1 100644
--- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
@@ -26,15 +26,16 @@ import com.cloud.utils.Pair;
 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;
@@ -51,7 +52,6 @@ import java.util.TimeZone;
 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 (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
@@ -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
@@ -539,21 +543,20 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, 
Long> implements Usage
     }
 
     @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) {
diff --git a/framework/db/src/main/java/com/cloud/utils/db/Filter.java 
b/framework/db/src/main/java/com/cloud/utils/db/Filter.java
index fb8c9ee37fc..90e42952a99 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/Filter.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/Filter.java
@@ -57,7 +57,8 @@ public class Filter {
     }
 
     public Filter(long limit) {
-        _orderBy = " ORDER BY RAND() LIMIT " + limit;
+        _orderBy = " ORDER BY RAND()";
+        _limit = limit;
     }
 
     public Filter(Long offset, Long limit) {
diff --git a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java 
b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java
index c3a4d2c2487..535fa032d23 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/GenericDaoBase.java
@@ -1161,6 +1161,8 @@ public abstract class GenericDaoBase<T, ID extends 
Serializable> extends Compone
                 if (filter.getLimit() != null) {
                     sql.append(", ").append(filter.getLimit());
                 }
+            } else if (filter.getLimit() != null) {
+                sql.append(" LIMIT ").append(filter.getLimit());
             }
         }
     }
@@ -1322,7 +1324,7 @@ public abstract class GenericDaoBase<T, ID extends 
Serializable> extends Compone
         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;
diff --git 
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java 
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 62b3c23d27e..3a4bdf8afec 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -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);
 
     private static final String IOPS_READ_RATE = "IOPS Read";
     private static final String IOPS_WRITE_RATE = "IOPS Write";
diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java 
b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java
index c46f1f43fd0..edaa22c3bcf 100644
--- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java
+++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java
@@ -26,6 +26,7 @@ import java.util.TimeZone;
 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;
@@ -489,7 +490,7 @@ public class UsageServiceImpl extends ManagerBase 
implements UsageService, Manag
                     }
                 }
             }
-            _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");
         }

Reply via email to