Hello Sergey Gotliv,

I'd like you to do a code review.  Please visit

    http://gerrit.ovirt.org/19521

to review the following change.

Change subject: engine: Split update of 'isPlugged' and 'bootOrder' 
properties...
......................................................................

engine: Split update of 'isPlugged' and 'bootOrder' properties...

HotPlugDiskToVmCommand updates 'isPlugged' and 'bootOrder' of all
devices attached to any particular VM. It should only update 'isPlugged'
for the device that was plugged by this command, otherwise it can cause a
race with another thread which handles the hot plug of another disk for
the same VM.

Change-Id: I1359a34a48a6261e22631ff1640d81d735e8c490
Bug-Url: https://bugzilla.redhat.com/1003649
Signed-off-by: Sergey Gotliv <[email protected]>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HotPlugDiskToVmCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/utils/VmDeviceUtils.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAO.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAODbFacadeImpl.java
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDeviceDAOTest.java
M packaging/dbscripts/vm_device_sp.sql
6 files changed, 89 insertions(+), 31 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/21/19521/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HotPlugDiskToVmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HotPlugDiskToVmCommand.java
index 00096dc..678bb19 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HotPlugDiskToVmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/HotPlugDiskToVmCommand.java
@@ -1,7 +1,7 @@
 package org.ovirt.engine.core.bll;
 
 import java.util.Collections;
-import java.util.List;
+import java.util.HashMap;
 import java.util.Map;
 
 import org.ovirt.engine.core.bll.utils.VmDeviceUtils;
@@ -40,13 +40,10 @@
 
     @Override
     protected boolean canDoAction() {
-        disk = getDiskDao().get(getParameters().getDiskId());
-
-        return
-                isVmExist() &&
+        return isVmExist() &&
                 isVmInUpPausedDownStatus() &&
                 canRunActionOnNonManagedVm() &&
-                isDiskExist(disk) &&
+                isDiskExist(getDisk()) &&
                 checkCanPerformPlugUnPlugDisk() &&
                 isVmNotInPreviewSnapshot() &&
                 imageStorageValidation();
@@ -56,10 +53,10 @@
         // If the VM is not an image then it does not use the storage domain.
         // If the VM is not in UP or PAUSED status, then we know that there is 
no running qemu process,
         // so we don't need to check the storage domain activity.
-        if (disk.getDiskStorageType() != DiskStorageType.IMAGE || 
!getVm().getStatus().isRunningOrPaused()) {
+        if (getDisk().getDiskStorageType() != DiskStorageType.IMAGE || 
!getVm().getStatus().isRunningOrPaused()) {
             return true;
         }
-        DiskImage diskImage = (DiskImage) disk;
+        DiskImage diskImage = (DiskImage) getDisk();
         StorageDomain storageDomain = getStorageDomainDAO().getForStoragePool(
                 diskImage.getStorageIds().get(0), 
diskImage.getStoragePoolId());
         StorageDomainValidator storageDomainValidator = 
getStorageDomainValidator(storageDomain);
@@ -75,9 +72,14 @@
         boolean returnValue = true;
         if (getVm().getStatus().isUpOrPaused()) {
             setVdsId(getVm().getRunOnVds());
-            returnValue =
-                    isHotPlugSupported() && isOsSupportingHotPlug()
-                            && isInterfaceSupportedForPlugUnPlug(disk);
+            if (!canPerformHotPlug() || 
!isInterfaceSupportedForPlugUnPlug(disk)) {
+                return false;
+            }
+        }
+
+        oldVmDevice = getVmDeviceDao().get(new VmDeviceId(getDisk().getId(), 
getVmId()));
+        if (getPlugAction() == VDSCommandType.HotPlugDisk && 
oldVmDevice.getIsPlugged()) {
+            return 
failCanDoAction(VdcBllMessages.HOT_PLUG_DISK_IS_NOT_UNPLUGGED);
         }
         if (returnValue) {
             oldVmDevice =
@@ -101,34 +103,59 @@
     @Override
     protected void executeVmCommand() {
         if (getVm().getStatus().isUpOrPaused()) {
-            performPlugCommand(getPlugAction(), disk, oldVmDevice);
+            performPlugCommand(getPlugAction(), getDisk(), oldVmDevice);
         }
 
-        //Update boot order and isPlugged fields
-        final List<VmDevice> devices = 
VmDeviceUtils.updateBootOrderInVmDevice(getVm().getStaticData());
-        for (VmDevice device:devices) {
-            if (device.getDeviceId().equals(oldVmDevice.getDeviceId())) {
-                device.setIsPlugged(!oldVmDevice.getIsPlugged());
-                break;
-            }
+        // At this point disk is already plugged to or unplugged from VM 
(depends on the command),
+        // so device's 'isPlugged' property should be updated accordingly in DB
+        updateDeviceIsPluggedProperty();
+
+        // Now after updating 'isPlugged' property of the plugged/unplugged 
device, its time to
+        // update the boot order for all VM devices. Failure to do that 
doesn't change the fact that
+        // device is already plugged to or unplugged from VM.
+        if (disk.isBoot()) {
+            updateBootOrder();
         }
 
+        getVmStaticDAO().incrementDbGeneration(getVm().getId());
+        setSucceeded(true);
+    }
+
+    private void updateDeviceIsPluggedProperty() {
+        VmDevice device = getVmDeviceDao().get(oldVmDevice.getId());
+        device.setIsPlugged(!oldVmDevice.getIsPlugged());
+        getVmDeviceDao().updateHotPlugDisk(device);
+    }
+
+    private void updateBootOrder() {
         TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
             @Override
             public Void runInTransaction() {
-                getVmStaticDAO().incrementDbGeneration(getVm().getId());
-                getVmDeviceDao().updateAll("UpdateVmDeviceForHotPlugDisk", 
devices);
-                VmHandler.updateDisksFromDb(getVm());
+                
VmDeviceUtils.updateBootOrderInVmDeviceAndStoreToDB(getVm().getStaticData());
                 return null;
             }
         });
-        setSucceeded(true);
     }
 
     @Override
     protected Map<String, Pair<String, String>> getSharedLocks() {
         return Collections.singletonMap(getVmId().toString(),
                 LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, 
VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED));
+    }
+
+    @Override
+    protected Map<String, Pair<String, String>> getExclusiveLocks() {
+        Map<String, Pair<String, String>> exclusiveLock = new HashMap<>();
+        exclusiveLock.put(getDisk().getId().toString(),
+                LockMessagesMatchUtil.makeLockingPair(LockingGroup.DISK,
+                        VdcBllMessages.ACTION_TYPE_FAILED_DISKS_LOCKED));
+        if (getDisk().isBoot()) {
+            exclusiveLock.put(getVmId().toString(),
+                
LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM_DISK_BOOT,
+                        VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED));
+
+        }
+        return exclusiveLock;
     }
 
     @Override
@@ -141,4 +168,10 @@
         return disk.getDiskAlias();
     }
 
+    protected Disk getDisk() {
+        if (disk == null) {
+            disk = getDiskDao().get(getParameters().getDiskId());
+        }
+        return disk;
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/utils/VmDeviceUtils.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/utils/VmDeviceUtils.java
index 0507ee1..0274c65 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/utils/VmDeviceUtils.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/utils/VmDeviceUtils.java
@@ -542,7 +542,7 @@
     public static void updateBootOrderInVmDeviceAndStoreToDB(VmBase vmBase) {
         List<VmDevice> devices = updateBootOrderInVmDevice(vmBase);
         for (VmDevice device : devices) {
-           dao.update(device);
+           dao.updateBootOrder(device);
         }
     }
 
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAO.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAO.java
index 075b8c3..153e6ba 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAO.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAO.java
@@ -61,4 +61,5 @@
      */
     void updateHotPlugDisk(VmDevice vmDevice);
 
+    void updateBootOrder(VmDevice vmDevice);
 }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAODbFacadeImpl.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAODbFacadeImpl.java
index 5840a7a..75f7c1f 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAODbFacadeImpl.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDeviceDAODbFacadeImpl.java
@@ -187,14 +187,18 @@
         return parameterSource;
     }
 
-
     @Override
     public void updateHotPlugDisk(VmDevice vmDevice) {
         MapSqlParameterSource paramsForUpdate = 
createParameterSourceForUpdate(vmDevice)
-            .addValue("boot_order",vmDevice.getBootOrder())
             .addValue("is_plugged",vmDevice.getIsPlugged());
         getCallsHandler().executeModification("UpdateVmDeviceForHotPlugDisk" , 
paramsForUpdate);
+    }
 
+    @Override
+    public void updateBootOrder(VmDevice vmDevice) {
+        MapSqlParameterSource paramsForUpdate = 
createParameterSourceForUpdate(vmDevice)
+                .addValue("boot_order",vmDevice.getBootOrder());
+        getCallsHandler().executeModification("UpdateVmDeviceBootOrder" , 
paramsForUpdate);
     }
 
     @Override
diff --git 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDeviceDAOTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDeviceDAOTest.java
index 80c5aa4..61d5378 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDeviceDAOTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDeviceDAOTest.java
@@ -183,14 +183,21 @@
     public void testUpdateHotPlugDisk() {
         VmDevice vmDevice = dao.get(getExistingEntityId());
         boolean newPluggedValue = !vmDevice.getIsPlugged();
-        int newBootOrderValue = vmDevice.getBootOrder() + 1;
         Assert.assertTrue(StringUtils.isNotBlank(vmDevice.getAddress()));
-        vmDevice.setBootOrder(newBootOrderValue);
         vmDevice.setIsPlugged(newPluggedValue);
         dao.updateHotPlugDisk(vmDevice);
         dao.get(getExistingEntityId());
         assertEquals(vmDevice.getIsPlugged(), newPluggedValue);
-        assertEquals(vmDevice.getBootOrder(),newBootOrderValue);
     }
 
+    @Test
+    public void testUpdateBootOrder() {
+        VmDevice vmDevice = dao.get(getExistingEntityId());
+        int newBootOrderValue = vmDevice.getBootOrder() + 1;
+        Assert.assertTrue(StringUtils.isNotBlank(vmDevice.getAddress()));
+        vmDevice.setBootOrder(newBootOrderValue);
+        dao.updateHotPlugDisk(vmDevice);
+        dao.get(getExistingEntityId());
+        assertEquals(vmDevice.getBootOrder(),newBootOrderValue);
+    }
 }
diff --git a/packaging/dbscripts/vm_device_sp.sql 
b/packaging/dbscripts/vm_device_sp.sql
index c6fd3bd..a5dbd1b 100644
--- a/packaging/dbscripts/vm_device_sp.sql
+++ b/packaging/dbscripts/vm_device_sp.sql
@@ -100,14 +100,12 @@
 Create or replace FUNCTION UpdateVmDeviceForHotPlugDisk(
     v_device_id UUID,
     v_vm_id UUID,
-    v_boot_order int,
     v_is_plugged boolean)
 RETURNS VOID
 AS $procedure$
 BEGIN
     UPDATE vm_device
     SET
-           boot_order = v_boot_order,
            is_plugged = v_is_plugged,
            _update_date = current_timestamp
     WHERE  device_id = v_device_id and vm_id = v_vm_id;
@@ -115,6 +113,21 @@
 LANGUAGE plpgsql;
 
 
+Create or replace FUNCTION UpdateVmDeviceBootOrder(
+    v_device_id UUID,
+    v_vm_id UUID,
+    v_boot_order int)
+RETURNS VOID
+AS $procedure$
+BEGIN
+    UPDATE vm_device
+    SET
+           boot_order = v_boot_order,
+           _update_date = current_timestamp
+    WHERE  device_id = v_device_id and vm_id = v_vm_id;
+END; $procedure$
+LANGUAGE plpgsql;
+
 
 Create or replace FUNCTION DeleteVmDevice(v_device_id UUID, v_vm_id UUID)
 RETURNS VOID


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1359a34a48a6261e22631ff1640d81d735e8c490
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.3
Gerrit-Owner: Tal Nisan <[email protected]>
Gerrit-Reviewer: Sergey Gotliv <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to