Arik Hadas has uploaded a new change for review.

Change subject: core: remove memory image on remove snapshot
......................................................................

core: remove memory image on remove snapshot

If snapshot contains memory and it is the only one that contains that
memory, remove the memory volumes when removing the snapshot as well.

Note that there might be cases where more than one snapshot contain the
same memory:
1. when preview snapshot, the memory volume is copied from the snapshot
that is being previewed to the active snapshot
2. when running vm in stateless mode, the memory volume is copied to
the active snapshot
3. in the future we might support cloning a VM with its memory
state (clone from snapshot + import as clone) and the memory would be
copied to the cloned VM's snapshots

Change-Id: Ib0b4f5306c23046326c9dbb7ef5589b50c88462d
Bug-Url: https://bugzilla.redhat.com/960931
Signed-off-by: Arik Hadas <aha...@redhat.com>
---
M backend/manager/dbscripts/snapshots_sp.sql
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java
5 files changed, 150 insertions(+), 25 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/78/15678/1

diff --git a/backend/manager/dbscripts/snapshots_sp.sql 
b/backend/manager/dbscripts/snapshots_sp.sql
index 6ea0304..30026b2 100644
--- a/backend/manager/dbscripts/snapshots_sp.sql
+++ b/backend/manager/dbscripts/snapshots_sp.sql
@@ -314,3 +314,16 @@
 END; $procedure$
 LANGUAGE plpgsql;
 
+
+Create or replace FUNCTION GetNumOfSnapshotsByMemoryVolume(
+    v_memory_volume VARCHAR(255))
+RETURNS SETOF BIGINT
+AS $procedure$
+BEGIN
+    RETURN QUERY
+    SELECT COUNT(*)
+    FROM   snapshots
+    WHERE  memory_volume = v_memory_volume;
+END; $procedure$
+LANGUAGE plpgsql;
+
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java
index af83f7e..f61dfac 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveSnapshotCommand.java
@@ -23,6 +23,7 @@
 import org.ovirt.engine.core.common.action.RemoveSnapshotParameters;
 import org.ovirt.engine.core.common.action.VdcActionType;
 import org.ovirt.engine.core.common.action.VdcReturnValueBase;
+import org.ovirt.engine.core.common.businessentities.Disk;
 import org.ovirt.engine.core.common.businessentities.DiskImage;
 import org.ovirt.engine.core.common.businessentities.Snapshot;
 import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotStatus;
@@ -33,9 +34,15 @@
 import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.common.errors.VdcBllMessages;
 import org.ovirt.engine.core.common.utils.Pair;
+import 
org.ovirt.engine.core.common.vdscommands.DeleteImageGroupVDSCommandParameters;
+import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
+import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
 import org.ovirt.engine.core.compat.Guid;
 import org.ovirt.engine.core.dao.SnapshotDao;
+import org.ovirt.engine.core.utils.GuidUtils;
 import org.ovirt.engine.core.utils.collections.MultiValueMapUtils;
+import org.ovirt.engine.core.utils.linq.LinqUtils;
+import org.ovirt.engine.core.utils.linq.Predicate;
 import org.ovirt.engine.core.utils.transaction.TransactionMethod;
 import org.ovirt.engine.core.utils.transaction.TransactionSupport;
 
@@ -88,47 +95,102 @@
             throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL);
         }
 
-        // If the VM hasn't got any images - simply remove the snapshot.
+        final Snapshot snapshot = 
getSnapshotDao().get(getParameters().getSnapshotId());
+
+        boolean snapshotHasImages = hasImages();
+        boolean removeSnapshotMemory = 
shouldRemoveMemorySnapshotVolumes(snapshot.getMemoryVolume());
+
+        // If the VM hasn't got any images and memory - simply remove the 
snapshot.
         // No need for locking, VDSM tasks, and all that jazz.
-        if (!hasImages()) {
+        if (!snapshotHasImages && !removeSnapshotMemory) {
             getSnapshotDao().remove(getParameters().getSnapshotId());
             setSucceeded(true);
             return;
         }
 
-        TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
-
-            @Override
-            public Void runInTransaction() {
-                Snapshot snapshot = 
getSnapshotDao().get(getParameters().getSnapshotId());
-                getCompensationContext().snapshotEntityStatus(snapshot, 
snapshot.getStatus());
-                getSnapshotDao().updateStatus(
-                        getParameters().getSnapshotId(), 
SnapshotStatus.LOCKED);
-                getCompensationContext().stateChanged();
-                return null;
-            }
-        });
+        lockSnapshot(snapshot);
         freeLock();
         getParameters().setEntityId(getVmId());
 
+        if (snapshotHasImages) {
+            removeImages();
+        }
+
+        if (removeSnapshotMemory) {
+            removeMemory(snapshot);
+        }
+
+        setSucceeded(true);
+    }
+
+    /**
+     * There is a one to many relation between memory volumes and snapshots, 
so memory
+     * volumes should be removed only if the only snapshot that points to them 
is removed
+     */
+    private boolean shouldRemoveMemorySnapshotVolumes(String memoryVolume) {
+        return !memoryVolume.isEmpty() &&
+                getSnapshotDao().getNumOfSnapshotsByMemory(memoryVolume) == 1;
+    }
+
+    private void removeMemory(final Snapshot snapshot) {
+        List<Guid> guids = 
GuidUtils.getGuidListFromString(snapshot.getMemoryVolume());
+
+        // get all vm disks in order to check post zero - if one of the
+        // disks is marked with wipe_after_delete
+        boolean postZero =
+                LinqUtils.filter(getDiskDao().getAllForVm(getVm().getId()),
+                        new Predicate<Disk>() {
+                    @Override
+                    public boolean eval(Disk disk) {
+                        return disk.isWipeAfterDelete();
+                    }
+                }).size() > 0;
+
+        // delete first image
+        // the next 'DeleteImageGroup' command should also take care of the
+        // image removal:
+        VDSReturnValue vdsRetValue = runVdsCommand(
+                VDSCommandType.DeleteImageGroup,
+                new DeleteImageGroupVDSCommandParameters(guids.get(1), 
guids.get(0), guids.get(2),
+                        postZero, false, 
getVm().getVdsGroupCompatibilityVersion().toString()));
+
+        if (!vdsRetValue.getSucceeded()) {
+            log.errorFormat("Cannot remove memory dump volume for snapshot 
{0}", snapshot.getId());
+        }
+        else {
+            Guid guid =
+                    createTask(vdsRetValue.getCreationInfo(), 
VdcActionType.RemoveSnapshot, VdcObjectType.Storage, guids.get(0));
+            getReturnValue().getTaskIdList().add(guid);
+        }
+
+        // delete second image
+        // the next 'DeleteImageGroup' command should also take care of the 
image removal:
+        vdsRetValue = runVdsCommand(
+                VDSCommandType.DeleteImageGroup,
+                new DeleteImageGroupVDSCommandParameters(guids.get(1), 
guids.get(0), guids.get(4),
+                        postZero, false, 
getVm().getVdsGroupCompatibilityVersion().toString()));
+
+        if (!vdsRetValue.getSucceeded()) {
+            log.errorFormat("Cannot remove memory metadata volume for snapshot 
{0}", snapshot.getId());
+        }
+        else {
+            Guid guid =
+                    createTask(vdsRetValue.getCreationInfo(), 
VdcActionType.RemoveSnapshot, VdcObjectType.Storage, guids.get(0));
+            getReturnValue().getTaskIdList().add(guid);
+        }
+    }
+
+    private void removeImages() {
         for (final DiskImage source : getSourceImages()) {
 
-            // The following line is ok because we have tested in the
-            // candoaction that the vm
+            // The following line is ok because we have tested in the 
candoaction that the vm
             // is not a template and the vm is not in preview mode and that
             // this is not the active snapshot.
             DiskImage dest = 
getDiskImageDao().getAllSnapshotsForParent(source.getImageId()).get(0);
 
-            ImagesContainterParametersBase tempVar = new 
ImagesContainterParametersBase(source.getImageId(),
-                    getVmId());
-            tempVar.setDestinationImageId(dest.getImageId());
-            tempVar.setEntityId(getParameters().getEntityId());
-            tempVar.setParentParameters(getParameters());
-            tempVar.setParentCommand(getActionType());
-            ImagesContainterParametersBase p = tempVar;
             VdcReturnValueBase vdcReturnValue = getBackend().runInternalAction(
                     VdcActionType.RemoveSnapshotSingleDisk,
-                    p,
+                    buildRemoveSnapshotSingleDiskParameters(source, dest),
                     
ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
 
             if (vdcReturnValue != null && 
vdcReturnValue.getInternalTaskIdList() != null) {
@@ -140,7 +202,31 @@
             quotasToRemoveFromCache.add(dest.getQuotaId());
             
QuotaManager.getInstance().removeQuotaFromCache(getStoragePoolId().getValue(), 
quotasToRemoveFromCache);
         }
-        setSucceeded(true);
+    }
+
+    private void lockSnapshot(final Snapshot snapshot) {
+        TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
+
+            @Override
+            public Void runInTransaction() {
+                getCompensationContext().snapshotEntityStatus(snapshot, 
snapshot.getStatus());
+                getSnapshotDao().updateStatus(
+                        getParameters().getSnapshotId(), 
SnapshotStatus.LOCKED);
+                getCompensationContext().stateChanged();
+                return null;
+            }
+        });
+    }
+
+    private ImagesContainterParametersBase 
buildRemoveSnapshotSingleDiskParameters(final DiskImage source,
+            DiskImage dest) {
+        ImagesContainterParametersBase parameters =
+                new ImagesContainterParametersBase(source.getImageId(), 
getVmId());
+        parameters.setDestinationImageId(dest.getImageId());
+        parameters.setEntityId(getParameters().getEntityId());
+        parameters.setParentParameters(getParameters());
+        parameters.setParentCommand(getActionType());
+        return parameters;
     }
 
     @Override
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java
index 200a0cb..33bde37 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDao.java
@@ -162,4 +162,6 @@
      * @return Whether a snapshot of the given ID exists for the VM or not.
      */
     boolean exists(Guid vmId, Guid snapshotId);
+
+    int getNumOfSnapshotsByMemory(String memoryVolume);
 }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java
index b90e975..d3e7972 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/SnapshotDaoDbFacadeImpl.java
@@ -213,6 +213,16 @@
                 parameterSource);
     }
 
+    @Override
+    public int getNumOfSnapshotsByMemory(String memoryVolume) {
+        MapSqlParameterSource parameterSource = 
getCustomMapSqlParameterSource()
+                .addValue("memory_volume", 
getNullableRepresentation(memoryVolume));
+
+        return getCallsHandler().executeRead("GetNumOfSnapshotsByMemoryVolume",
+                getIntegerMapper(),
+                parameterSource);
+    }
+
     private String getNullableRepresentation(String memoryVolume) {
         return memoryVolume.isEmpty() ? null : memoryVolume;
     }
diff --git 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java
index a166856..0862c6d 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/SnapshotDaoTest.java
@@ -24,6 +24,10 @@
 
     private static final Guid EXISTING_VM_ID = new 
Guid("77296e00-0cad-4e5a-9299-008a7b6f4355");
     private static final Guid EXISTING_SNAPSHOT_ID = new 
Guid("a7bb24df-9fdf-4bd6-b7a9-f5ce52da0f89");
+    private static final String EXISTING_MEMORY_VOLUME =
+            
"11111111-1111-1111-1111-111111111111,22222222-2222-2222-2222-222222222222,33333333-3333-3333-3333-333333333333,44444444-4444-4444-4444-444444444444,55555555-5555-5555-5555-555555555555,66666666-6666-6666-6666-666666666666";
+    private static final String NON_EXISTING_MEMORY_VOLUME =
+            
"21111111-1111-1111-1111-111111111111,22222222-2222-2222-2222-222222222222,33333333-3333-3333-3333-333333333333,44444444-4444-4444-4444-444444444444,55555555-5555-5555-5555-555555555555,66666666-6666-6666-6666-666666666666";
     private static final int TOTAL_SNAPSHOTS = 2;
 
     @Override
@@ -109,6 +113,16 @@
     }
 
     @Test
+    public void getZeroSnapshotsByMemory() {
+        
assertEquals(dao.getNumOfSnapshotsByMemory(NON_EXISTING_MEMORY_VOLUME), 0);
+    }
+
+    @Test
+    public void getOneSnapshotsByMemory() {
+        assertEquals(dao.getNumOfSnapshotsByMemory(EXISTING_MEMORY_VOLUME), 1);
+    }
+
+    @Test
     public void getSnaphsotByTypeReturnsIdForExistingByTypeAndStatus() throws 
Exception {
         assertNotNull(dao.get(EXISTING_VM_ID, SnapshotType.REGULAR));
     }


-- 
To view, visit http://gerrit.ovirt.org/15678
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib0b4f5306c23046326c9dbb7ef5589b50c88462d
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Arik Hadas <aha...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to