Skip to content

Commit ca6075e

Browse files
committed
snapshot: look up a duplicate snapshot name by volume and name
Query for an active snapshot with the given name on the volume instead of listing every snapshot of the volume and comparing names, as asked in review.
1 parent b229715 commit ca6075e

4 files changed

Lines changed: 22 additions & 8 deletions

File tree

‎engine/schema/src/main/java/com/cloud/storage/dao/SnapshotDao.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public interface SnapshotDao extends GenericDao<SnapshotVO, Long>, StateDao<Snap
5353

5454
List<SnapshotVO> listByStatusNotIn(long volumeId, Snapshot.State... status);
5555

56+
SnapshotVO findByVolumeIdAndNameNotInStatus(long volumeId, String name, Snapshot.State... status);
57+
5658
/**
5759
* Retrieves a list of snapshots filtered by ids.
5860
* @param ids Snapshot ids.

‎engine/schema/src/main/java/com/cloud/storage/dao/SnapshotDaoImpl.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
6565
private SearchBuilder<SnapshotVO> InstanceIdSearch;
6666
private SearchBuilder<SnapshotVO> StatusSearch;
6767
private SearchBuilder<SnapshotVO> notInStatusSearch;
68+
private SearchBuilder<SnapshotVO> volumeIdNameNotInStatusSearch;
6869
private GenericSearchBuilder<SnapshotVO, Long> CountSnapshotsByAccount;
6970
@Inject
7071
ResourceTagDao _tagsDao;
@@ -159,6 +160,12 @@ protected void init() {
159160
notInStatusSearch.and("status", notInStatusSearch.entity().getState(), SearchCriteria.Op.NOTIN);
160161
notInStatusSearch.done();
161162

163+
volumeIdNameNotInStatusSearch = createSearchBuilder();
164+
volumeIdNameNotInStatusSearch.and("volumeId", volumeIdNameNotInStatusSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
165+
volumeIdNameNotInStatusSearch.and("name", volumeIdNameNotInStatusSearch.entity().getName(), SearchCriteria.Op.EQ);
166+
volumeIdNameNotInStatusSearch.and("status", volumeIdNameNotInStatusSearch.entity().getState(), SearchCriteria.Op.NOTIN);
167+
volumeIdNameNotInStatusSearch.done();
168+
162169
CountSnapshotsByAccount = createSearchBuilder(Long.class);
163170
CountSnapshotsByAccount.select(null, Func.COUNT, null);
164171
CountSnapshotsByAccount.and("account", CountSnapshotsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
@@ -295,6 +302,15 @@ public List<SnapshotVO> listByStatusNotIn(long volumeId, Snapshot.State... statu
295302
return listBy(sc, null);
296303
}
297304

305+
@Override
306+
public SnapshotVO findByVolumeIdAndNameNotInStatus(long volumeId, String name, Snapshot.State... status) {
307+
SearchCriteria<SnapshotVO> sc = volumeIdNameNotInStatusSearch.create();
308+
sc.setParameters("volumeId", volumeId);
309+
sc.setParameters("name", name);
310+
sc.setParameters("status", (Object[]) status);
311+
return findOneBy(sc);
312+
}
313+
298314
@Override
299315
public List<SnapshotVO> searchByVolumes(List<Long> volumeIds) {
300316
if (CollectionUtils.isEmpty(volumeIds)) {

‎server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,10 +1721,8 @@ public Snapshot allocSnapshot(Long volumeId, Long policyId, String snapshotName,
17211721
if (snapshotName == null)
17221722
snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString;
17231723

1724-
for (SnapshotVO existingSnapshot : _snapshotDao.listByStatusNotIn(volumeId, Snapshot.State.Destroyed, Snapshot.State.Error)) {
1725-
if (snapshotName.equals(existingSnapshot.getName())) {
1726-
throw new InvalidParameterValueException(String.format("A snapshot with name [%s] already exists for volume %s.", snapshotName, volume));
1727-
}
1724+
if (_snapshotDao.findByVolumeIdAndNameNotInStatus(volumeId, snapshotName, Snapshot.State.Destroyed, Snapshot.State.Error) != null) {
1725+
throw new InvalidParameterValueException(String.format("A snapshot with name [%s] already exists for volume %s.", snapshotName, volume));
17281726
}
17291727

17301728
HypervisorType hypervisorType = HypervisorType.None;

‎server/src/test/java/com/cloud/storage/snapshot/SnapshotManagerImplTest.java‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ public void testAllocSnapshotRejectsDuplicateNameForVolume() {
121121
Mockito.when(volume.getInstanceId()).thenReturn(null);
122122
Mockito.when(volume.getAccountId()).thenReturn(2L);
123123

124-
SnapshotVO existing = Mockito.mock(SnapshotVO.class);
125-
Mockito.when(existing.getName()).thenReturn("dup");
126-
Mockito.when(snapshotDao.listByStatusNotIn(volumeId, Snapshot.State.Destroyed, Snapshot.State.Error))
127-
.thenReturn(List.of(existing));
124+
Mockito.when(snapshotDao.findByVolumeIdAndNameNotInStatus(volumeId, "dup", Snapshot.State.Destroyed, Snapshot.State.Error))
125+
.thenReturn(Mockito.mock(SnapshotVO.class));
128126

129127
Assert.assertThrows(InvalidParameterValueException.class, () ->
130128
snapshotManager.allocSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, "dup", null));

0 commit comments

Comments
 (0)