Copilot commented on code in PR #12481:
URL: https://github.com/apache/cloudstack/pull/12481#discussion_r2711297816


##########
api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java:
##########
@@ -244,8 +244,7 @@ public void execute() {
     }
 
     private Snapshot.LocationType getLocationType() {
-
-        if (Snapshot.LocationType.values() == null || 
Snapshot.LocationType.values().length == 0 || locationType == null) {
+        if (Snapshot.LocationType.values().length == 0 || locationType == 
null) {

Review Comment:
   The check for Snapshot.LocationType.values().length == 0 is redundant since 
the LocationType enum has two defined values (PRIMARY and SECONDARY) and will 
never have a length of 0. Consider removing this check as well to simplify the 
condition to just checking if locationType is null.
   ```suggestion
           if (locationType == null) {
   ```



##########
server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java:
##########
@@ -1485,15 +1493,17 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) 
throws ResourceAllocationExc
             if (logger.isDebugEnabled()) {
                 logger.debug("Failed to create snapshot" + 
cre.getLocalizedMessage());
             }
+            ResourceType storeResourceType = 
getStoreResourceType(volume.getDataCenterId(), payload.getLocationType());
             _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.snapshot);
-            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.secondary_storage, new Long(volume.getSize()));
+            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
storeResourceType, new Long(volume.getSize()));
             throw cre;
         } catch (Exception e) {
             if (logger.isDebugEnabled()) {
                 logger.debug("Failed to create snapshot", e);
             }
+            ResourceType storeResourceType = 
getStoreResourceType(volume.getDataCenterId(), payload.getLocationType());
             _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.snapshot);
-            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.secondary_storage, new Long(volume.getSize()));
+            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
storeResourceType, new Long(volume.getSize()));

Review Comment:
   Inefficient constructor for long value, use Long.valueOf(...) instead.



##########
engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDaoImpl.java:
##########
@@ -78,6 +78,15 @@ public class SnapshotDataStoreDaoImpl extends 
GenericDaoBase<SnapshotDataStoreVO
             " order by created %s " +
             " limit 1";
 
+    private static final String 
GET_PHYSICAL_SIZE_OF_SNAPSHOTS_ON_PRIMARY_BY_ACCOUNT = "SELECT 
SUM(s.physical_size) " +
+            "FROM cloud.snapshot_store_ref s " +
+            "INNER JOIN cloud.snapshots ON s.snapshot_id = snapshots.id " +
+            "WHERE snapshots.account_id = ? " +
+            "AND snapshots.removed IS NULL " +
+            "AND s.state = 'Ready' " +
+            "AND s.store_role = 'Primary' " +
+            "AND NOT EXISTS (SELECT 1 FROM cloud.snapshot_store_ref i WHERE 
i.snapshot_id = s.snapshot_id AND i.store_role = 'Image')";

Review Comment:
   The SQL query uses a NOT EXISTS subquery which could be inefficient on large 
datasets. Consider adding appropriate indexes on snapshot_store_ref.snapshot_id 
and snapshot_store_ref.store_role, or restructuring the query to use a LEFT 
JOIN with IS NULL check for better performance. Additionally, ensure that 
indexes exist on snapshots.account_id and snapshots.removed for optimal query 
performance.
   ```suggestion
               "LEFT JOIN cloud.snapshot_store_ref i ON i.snapshot_id = 
s.snapshot_id AND i.store_role = 'Image' " +
               "WHERE snapshots.account_id = ? " +
               "AND snapshots.removed IS NULL " +
               "AND s.state = 'Ready' " +
               "AND s.store_role = 'Primary' " +
               "AND i.snapshot_id IS NULL";
   ```



##########
engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDaoImpl.java:
##########
@@ -578,4 +586,23 @@ public int expungeBySnapshotList(final List<Long> 
snapshotIds, final Long batchS
         sc.setParameters("snapshotIds", snapshotIds.toArray());
         return batchExpunge(sc, batchSize);
     }
+
+    @Override
+    public long getSnapshotsPhysicalSizeOnPrimaryStorageByAccountId(long 
accountId) {
+        long snapshotsPhysicalSize = 0;
+        try (TransactionLegacy transactionLegacy = 
TransactionLegacy.currentTxn()) {
+            try (PreparedStatement preparedStatement = 
transactionLegacy.prepareStatement(GET_PHYSICAL_SIZE_OF_SNAPSHOTS_ON_PRIMARY_BY_ACCOUNT))
 {
+                preparedStatement.setLong(1, accountId);
+
+                try (ResultSet resultSet = preparedStatement.executeQuery()) {
+                    if (resultSet.next()) {
+                        snapshotsPhysicalSize = resultSet.getLong(1);
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            logger.warn("Failed to get the snapshots physical size for the 
account [{}] due to [{}].", accountId, e.getMessage(), e);
+        }
+        return snapshotsPhysicalSize;
+    }

Review Comment:
   The new method getSnapshotsPhysicalSizeOnPrimaryStorageByAccountId lacks 
direct unit or integration tests. While it is tested through mocking in 
ResourceLimitManagerImplTest, consider adding a test case in 
SnapshotDataStoreDaoImplTest or creating an integration test that validates the 
SQL query behavior with actual database data, especially for edge cases like 
accounts with no snapshots, null physical sizes, or the NOT EXISTS clause 
conditions.



##########
engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDaoImpl.java:
##########
@@ -578,4 +586,23 @@ public int expungeBySnapshotList(final List<Long> 
snapshotIds, final Long batchS
         sc.setParameters("snapshotIds", snapshotIds.toArray());
         return batchExpunge(sc, batchSize);
     }
+
+    @Override
+    public long getSnapshotsPhysicalSizeOnPrimaryStorageByAccountId(long 
accountId) {
+        long snapshotsPhysicalSize = 0;
+        try (TransactionLegacy transactionLegacy = 
TransactionLegacy.currentTxn()) {
+            try (PreparedStatement preparedStatement = 
transactionLegacy.prepareStatement(GET_PHYSICAL_SIZE_OF_SNAPSHOTS_ON_PRIMARY_BY_ACCOUNT))
 {
+                preparedStatement.setLong(1, accountId);
+
+                try (ResultSet resultSet = preparedStatement.executeQuery()) {
+                    if (resultSet.next()) {
+                        snapshotsPhysicalSize = resultSet.getLong(1);
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            logger.warn("Failed to get the snapshots physical size for the 
account [{}] due to [{}].", accountId, e.getMessage(), e);
+        }
+        return snapshotsPhysicalSize;
+    }

Review Comment:
   The method getSnapshotsPhysicalSizeOnPrimaryStorageByAccountId could benefit 
from handling the null case explicitly for clarity. When SUM() returns NULL (no 
matching rows), resultSet.getLong(1) will return 0 by default, but this 
behavior is implicit. Consider using resultSet.wasNull() to check if the SUM 
returned NULL and explicitly return 0, or add a COALESCE in the SQL query to 
make the intent clearer.



##########
server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java:
##########
@@ -1472,8 +1479,9 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) 
throws ResourceAllocationExc
                 
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, 
snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, 
snapshot.getName(), null, null,
                         snapshotStoreRef.getPhysicalSize(), volume.getSize(), 
snapshot.getClass().getName(), snapshot.getUuid());
 
+                ResourceType storeResourceType = dataStoreRole == 
DataStoreRole.Image ? ResourceType.secondary_storage : 
ResourceType.primary_storage;
                 // Correct the resource count of snapshot in case of delta 
snapshots.
-                
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.secondary_storage, new Long(volume.getSize() - 
snapshotStoreRef.getPhysicalSize()));
+                
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
storeResourceType, new Long(volume.getSize() - 
snapshotStoreRef.getPhysicalSize()));

Review Comment:
   Inefficient constructor for long value, use Long.valueOf(...) instead.



##########
engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java:
##########
@@ -110,4 +110,6 @@ public interface SnapshotDataStoreDao extends 
GenericDao<SnapshotDataStoreVO, Lo
     void updateDisplayForSnapshotStoreRole(long snapshotId, long storeId, 
DataStoreRole role, boolean display);
 
     int expungeBySnapshotList(List<Long> snapshotIds, Long batchSize);
+

Review Comment:
   The new method getSnapshotsPhysicalSizeOnPrimaryStorageByAccountId lacks 
documentation. Consider adding a JavaDoc comment that describes what the method 
does, its parameters, return value, and any important behavior (e.g., that it 
only returns snapshots on primary storage that haven't been backed up to 
secondary storage, and returns 0 if no snapshots are found).
   ```suggestion
   
       /**
        * Returns the total physical size, in bytes, of all snapshots stored on 
primary
        * storage for the specified account that have not yet been backed up to
        * secondary storage.
        *
        * <p>If no such snapshots are found, this method returns {@code 0}.</p>
        *
        * @param accountId the ID of the account whose snapshots on primary 
storage
        *                  should be considered
        * @return the total physical size in bytes of matching snapshots on 
primary
        *         storage, or {@code 0} if none are found
        */
   ```



##########
server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java:
##########
@@ -1485,15 +1493,17 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) 
throws ResourceAllocationExc
             if (logger.isDebugEnabled()) {
                 logger.debug("Failed to create snapshot" + 
cre.getLocalizedMessage());
             }
+            ResourceType storeResourceType = 
getStoreResourceType(volume.getDataCenterId(), payload.getLocationType());
             _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.snapshot);
-            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
ResourceType.secondary_storage, new Long(volume.getSize()));
+            _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), 
storeResourceType, new Long(volume.getSize()));

Review Comment:
   Inefficient constructor for long value, use Long.valueOf(...) instead.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to