From 1d352f1e2cb09ae324de3c1b5f2b577af32527d3 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Fri, 13 Jan 2012 15:19:14 -0800 Subject: [PATCH] bug 12148: add checkpoint for storage migration status 12148: resolved fixed --- .../computing/LibvirtComputingResource.java | 23 ++-- .../cloud/cluster/CheckPointManagerImpl.java | 10 +- .../com/cloud/cluster/dao/StackMaidDao.java | 3 +- .../cloud/cluster/dao/StackMaidDaoImpl.java | 29 +++++ .../com/cloud/storage/StorageManagerImpl.java | 14 ++- .../storage/StorageMigrationCleanupMaid.java | 105 ++++++++++++++++++ 6 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 server/src/com/cloud/storage/StorageMigrationCleanupMaid.java diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index 07ea644c16f..26e477f801e 100755 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -2340,13 +2340,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } } - - // Attach each data volume to the VM, if there is a deferred attached disk - for (DiskDef disk : vm.getDevices().getDisks()) { - if (disk.isAttachDeferred()) { - attachOrDetachDevice(conn, true, vmName, disk.toString()); - } - } state = State.Running; return new StartAnswer(cmd); @@ -2416,18 +2409,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv if (pool.getType() == StoragePoolType.CLVM) { disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusType); } else { - disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2); + if (volume.getType() == Volume.Type.DATADISK) { + disk.defFileBasedDisk(physicalDisk.getPath(), devId, DiskDef.diskBus.VIRTIO, DiskDef.diskFmtType.QCOW2); + } else { + disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2); + } } } - //Centos doesn't support scsi hotplug. For other host OSes, we attach the disk after the vm is running, so that we can hotplug it. - if (volume.getType() == Volume.Type.DATADISK && diskBusType != DiskDef.diskBus.VIRTIO) { - disk.setAttachDeferred(true); - } - - if (!disk.isAttachDeferred()) { - vm.getDevices().addDevice(disk); - } + vm.getDevices().addDevice(disk); + } if (vmSpec.getType() != VirtualMachine.Type.User) { diff --git a/server/src/com/cloud/cluster/CheckPointManagerImpl.java b/server/src/com/cloud/cluster/CheckPointManagerImpl.java index 7e0f357b63e..e14fbe1c7f1 100644 --- a/server/src/com/cloud/cluster/CheckPointManagerImpl.java +++ b/server/src/com/cloud/cluster/CheckPointManagerImpl.java @@ -206,14 +206,16 @@ public class CheckPointManagerImpl implements CheckPointManager, Manager, Cluste } class CleanupTask implements Runnable { - - public CleanupTask() { + private Date _curDate; + public CleanupTask() { + _curDate = new Date(); } @Override public void run() { - try { - List tasks = _maidDao.listCleanupTasks(_msId); + try { + List tasks = _maidDao.listLeftoversByCutTime(_curDate, _msId); + tasks.addAll(_maidDao.listCleanupTasks(_msId)); List retries = new ArrayList(); diff --git a/server/src/com/cloud/cluster/dao/StackMaidDao.java b/server/src/com/cloud/cluster/dao/StackMaidDao.java index 9fc9497d90e..5164eb94e65 100644 --- a/server/src/com/cloud/cluster/dao/StackMaidDao.java +++ b/server/src/com/cloud/cluster/dao/StackMaidDao.java @@ -44,5 +44,6 @@ public interface StackMaidDao extends GenericDao { */ boolean takeover(long takeOverMsid, long selfId); - List listCleanupTasks(long selfId); + List listCleanupTasks(long selfId); + List listLeftoversByCutTime(Date cutTime, long msid); } diff --git a/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java b/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java index fe72f1e7838..5748ea41fdb 100644 --- a/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java +++ b/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java @@ -174,6 +174,35 @@ public class StackMaidDaoImpl extends GenericDaoBase impleme txn.close(); } return l; + } + + @Override + @DB + public List listLeftoversByCutTime(Date cutTime, long msid) { + + List l = new ArrayList(); + String sql = "select * from stack_maid where created < ? and msid = ? order by msid asc, thread_id asc, seq desc"; + + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + String gmtCutTime = DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime); + pstmt.setString(1, gmtCutTime); + pstmt.setLong(2, msid); + + ResultSet rs = pstmt.executeQuery(); + while(rs.next()) { + l.add(toEntityBean(rs, false)); + } + } catch (SQLException e) { + s_logger.error("unexcpected exception " + e.getMessage(), e); + } catch (Throwable e) { + s_logger.error("unexcpected exception " + e.getMessage(), e); + } finally { + txn.close(); + } + return l; } } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index a7f528ebabc..17be2bfc8b3 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -75,6 +75,7 @@ import com.cloud.async.AsyncJobManager; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.cluster.CheckPointManager; import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.configuration.Config; @@ -299,6 +300,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag protected SecondaryStorageVmManager _ssvmMgr; @Inject protected ResourceManager _resourceMgr; + @Inject + protected CheckPointManager _checkPointMgr; @Inject(adapter = StoragePoolAllocator.class) protected Adapters _storagePoolAllocators; @@ -2636,7 +2639,9 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag txn.start(); boolean transitResult = false; + long checkPointTaskId = -1; try { + List volIds = new ArrayList(); for (Volume volume : volumes) { if (!_snapshotMgr.canOperateOnVolume((VolumeVO)volume)) { throw new CloudRuntimeException("There are snapshots creating on this volume, can not move this volume"); @@ -2650,8 +2655,10 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag s_logger.debug("Failed to set state into migrate: " + e.toString()); throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString()); } + volIds.add(volume.getId()); } + checkPointTaskId = _checkPointMgr.pushCheckPoint(new StorageMigrationCleanupMaid(StorageMigrationCleanupMaid.StorageMigrationState.MIGRATING, volIds)); transitResult = true; } finally { if (!transitResult) { @@ -2708,6 +2715,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag s_logger.debug("Failed to change volume state: " + e.toString()); } } + _checkPointMgr.popCheckPoint(checkPointTaskId); } else { //Need a transaction, make sure all the volumes get migrated to new storage pool txn = Transaction.currentTxn(); @@ -2732,8 +2740,12 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag throw new CloudRuntimeException("Failed to change volume state: " + e.toString()); } } - transitResult = true; + try { + _checkPointMgr.popCheckPoint(checkPointTaskId); + } catch (Exception e) { + + } } finally { if (!transitResult) { txn.rollback(); diff --git a/server/src/com/cloud/storage/StorageMigrationCleanupMaid.java b/server/src/com/cloud/storage/StorageMigrationCleanupMaid.java new file mode 100644 index 00000000000..d3848e89c25 --- /dev/null +++ b/server/src/com/cloud/storage/StorageMigrationCleanupMaid.java @@ -0,0 +1,105 @@ +package com.cloud.storage; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.cloud.cluster.CheckPointManager; +import com.cloud.cluster.CleanupMaid; +import com.cloud.server.ManagementServer; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.VMInstanceDao; + +public class StorageMigrationCleanupMaid implements CleanupMaid { + private static final Logger s_logger = Logger.getLogger(StorageMigrationCleanupMaid.class); + public static enum StorageMigrationState { + MIGRATING, + MIGRATINGFAILED, + MIGRATINGSUCCESS; + } + + private List _volumesIds = new ArrayList(); + private StorageMigrationState _migrateState; + + public StorageMigrationCleanupMaid() { + + } + + public StorageMigrationCleanupMaid(StorageMigrationState state, List volumes) { + _migrateState = state; + _volumesIds = volumes; + } + + public void updateStaste(StorageMigrationState state) { + _migrateState = state; + } + + @Override + public int cleanup(CheckPointManager checkPointMgr) { + StateMachine2 _stateMachine = Volume.State.getStateMachine(); + + ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); + VolumeDao volDao = locator.getDao(VolumeDao.class); + VMInstanceDao vmDao = locator.getDao(VMInstanceDao.class); + VirtualMachineManager vmMgr = locator.getManager(VirtualMachineManager.class); + Long vmInstanceId = null; + boolean success = true; + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + + try { + txn.start(); + for (Long volumeId : _volumesIds) { + VolumeVO volume = volDao.findById(volumeId); + if (volume == null) { + continue; + } + vmInstanceId = volume.getInstanceId(); + if (_migrateState == StorageMigrationState.MIGRATING && volume.getState() == Volume.State.Migrating) { + try { + _stateMachine.transitTo(volume, Volume.Event.OperationFailed, null, volDao); + } catch (NoTransitionException e) { + s_logger.debug("Failed to transit volume state: " + e.toString()); + success = false; + break; + } + } + } + if (vmInstanceId != null) { + VMInstanceVO vm = vmDao.findById(vmInstanceId); + if (vm != null && vm.getState() == VirtualMachine.State.Migrating) { + try { + vmMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportStopped, null); + } catch (NoTransitionException e) { + s_logger.debug("Failed to transit vm state"); + success = false; + } + } + } + + if (success) { + txn.commit(); + } + } catch (Exception e) { + s_logger.debug("storage migration cleanup failed:" + e.toString()); + txn.rollback(); + }finally { + txn.close(); + } + + return 0; + } + + @Override + public String getCleanupProcedure() { + return null; + } + +}