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]