diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java index d0b9be99678..463c0ff3538 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import com.cloud.agent.api.Answer; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; @@ -33,4 +34,10 @@ public interface VolumeInfo extends DataObject, Volume { public Long getLastPoolId(); public String getAttachedVmName(); + + public void processEventOnly(ObjectInDataStoreStateMachine.Event event); + + public void processEventOnly(ObjectInDataStoreStateMachine.Event event, Answer answer); + + public boolean stateTransit(Volume.Event event); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index bc14b6ac673..1e2f00044bb 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -126,6 +126,7 @@ public class VolumeObject implements VolumeInfo { return volumeVO.getId(); } + @Override public boolean stateTransit(Volume.Event event) { boolean result = false; try { @@ -236,6 +237,22 @@ public class VolumeObject implements VolumeInfo { } + @Override + public void processEventOnly(ObjectInDataStoreStateMachine.Event event) { + try { + objectInStoreMgr.update(this, event); + } catch (Exception e) { + s_logger.debug("Failed to update state", e); + throw new CloudRuntimeException("Failed to update state:" + e.toString()); + } finally { + // in case of OperationFailed, expunge the entry + if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + objectInStoreMgr.delete(this); + } + } + } + + @Override public String getName() { return this.volumeVO.getName(); @@ -434,6 +451,56 @@ public class VolumeObject implements VolumeInfo { } + @Override + public void processEventOnly(ObjectInDataStoreStateMachine.Event event, Answer answer) { + try { + if (this.dataStore.getRole() == DataStoreRole.Primary) { + if (answer instanceof CopyCmdAnswer) { + CopyCmdAnswer cpyAnswer = (CopyCmdAnswer) answer; + VolumeVO vol = this.volumeDao.findById(this.getId()); + VolumeObjectTO newVol = (VolumeObjectTO) cpyAnswer.getNewData(); + vol.setPath(newVol.getPath()); + vol.setSize(newVol.getSize()); + vol.setPoolId(this.getDataStore().getId()); + volumeDao.update(vol.getId(), vol); + } else if (answer instanceof CreateObjectAnswer) { + CreateObjectAnswer createAnswer = (CreateObjectAnswer) answer; + VolumeObjectTO newVol = (VolumeObjectTO) createAnswer.getData(); + VolumeVO vol = this.volumeDao.findById(this.getId()); + vol.setPath(newVol.getPath()); + vol.setSize(newVol.getSize()); + vol.setPoolId(this.getDataStore().getId()); + volumeDao.update(vol.getId(), vol); + } + } else { + // image store or imageCache store + if (answer instanceof DownloadAnswer) { + DownloadAnswer dwdAnswer = (DownloadAnswer) answer; + VolumeDataStoreVO volStore = this.volumeStoreDao.findByStoreVolume(this.dataStore.getId(), + this.getId()); + volStore.setInstallPath(dwdAnswer.getInstallPath()); + volStore.setChecksum(dwdAnswer.getCheckSum()); + this.volumeStoreDao.update(volStore.getId(), volStore); + } else if (answer instanceof CopyCmdAnswer) { + CopyCmdAnswer cpyAnswer = (CopyCmdAnswer) answer; + VolumeDataStoreVO volStore = this.volumeStoreDao.findByStoreVolume(this.dataStore.getId(), + this.getId()); + VolumeObjectTO newVol = (VolumeObjectTO) cpyAnswer.getNewData(); + volStore.setInstallPath(newVol.getPath()); + volStore.setSize(newVol.getSize()); + this.volumeStoreDao.update(volStore.getId(), volStore); + } + } + } catch (RuntimeException ex) { + if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + objectInStoreMgr.delete(this); + } + throw ex; + } + this.processEventOnly(event); + + } + @Override public ImageFormat getFormat() { return this.volumeVO.getFormat(); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 51516830653..99aac17e3da 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -623,6 +623,7 @@ public class VolumeServiceImpl implements VolumeService { srcVolume.processEvent(Event.OperationFailed); res.setResult(result.getResult()); future.complete(res); + return null; } srcVolume.processEvent(Event.OperationSuccessed); @@ -643,8 +644,8 @@ public class VolumeServiceImpl implements VolumeService { VolumeInfo destVolume = null; try { destVolume = (VolumeInfo)destStore.create(srcVolume); - destVolume.processEvent(Event.CreateOnlyRequested); - srcVolume.processEvent(Event.CopyingRequested); // this is just used for locking that src volume record in DB to avoid using lock + srcVolume.processEvent(Event.MigrationRequested); // this is just used for locking that src volume record in DB to avoid using lock + destVolume.processEventOnly(Event.CreateOnlyRequested); CopyVolumeContext context = new CopyVolumeContext(null, future, srcVolume, destVolume, @@ -658,7 +659,7 @@ public class VolumeServiceImpl implements VolumeService { } catch (Exception e) { s_logger.error("failed to copy volume to image store", e); if (destVolume != null) { - destVolume.processEvent(Event.OperationFailed); + destVolume.getDataStore().delete(destVolume); } srcVolume.processEvent(Event.OperationFailed); // unlock source volume record res.setResult(e.toString()); @@ -675,13 +676,13 @@ public class VolumeServiceImpl implements VolumeService { VolumeApiResult res = new VolumeApiResult(destVolume); try { if (res.isFailed()) { - destVolume.processEvent(Event.OperationFailed); - srcVolume.processEvent(Event.OperationFailed); + srcVolume.processEvent(Event.OperationFailed); // back to Ready state in Volume table + destVolume.processEventOnly(Event.OperationFailed); res.setResult(result.getResult()); future.complete(res); }else{ - srcVolume.processEvent(Event.OperationSuccessed); - destVolume.processEvent(Event.OperationSuccessed, result.getAnswer()); + srcVolume.processEvent(Event.OperationSuccessed); // back to Ready state in Volume table + destVolume.processEventOnly(Event.OperationSuccessed, result.getAnswer()); future.complete(res); } } catch (Exception e) {