bug 12148: add checkpoint for storage migration

status 12148: resolved fixed
This commit is contained in:
Edison Su 2012-01-13 15:19:14 -08:00
parent 1a3a3f8e0d
commit 1d352f1e2c
6 changed files with 162 additions and 22 deletions

View File

@ -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) {

View File

@ -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<CheckPointVO> tasks = _maidDao.listCleanupTasks(_msId);
try {
List<CheckPointVO> tasks = _maidDao.listLeftoversByCutTime(_curDate, _msId);
tasks.addAll(_maidDao.listCleanupTasks(_msId));
List<CheckPointVO> retries = new ArrayList<CheckPointVO>();

View File

@ -44,5 +44,6 @@ public interface StackMaidDao extends GenericDao<CheckPointVO, Long> {
*/
boolean takeover(long takeOverMsid, long selfId);
List<CheckPointVO> listCleanupTasks(long selfId);
List<CheckPointVO> listCleanupTasks(long selfId);
List<CheckPointVO> listLeftoversByCutTime(Date cutTime, long msid);
}

View File

@ -174,6 +174,35 @@ public class StackMaidDaoImpl extends GenericDaoBase<CheckPointVO, Long> impleme
txn.close();
}
return l;
}
@Override
@DB
public List<CheckPointVO> listLeftoversByCutTime(Date cutTime, long msid) {
List<CheckPointVO> l = new ArrayList<CheckPointVO>();
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;
}
}

View File

@ -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<StoragePoolAllocator> _storagePoolAllocators;
@ -2636,7 +2639,9 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
txn.start();
boolean transitResult = false;
long checkPointTaskId = -1;
try {
List<Long> volIds = new ArrayList<Long>();
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();

View File

@ -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<Long> _volumesIds = new ArrayList<Long>();
private StorageMigrationState _migrateState;
public StorageMigrationCleanupMaid() {
}
public StorageMigrationCleanupMaid(StorageMigrationState state, List<Long> volumes) {
_migrateState = state;
_volumesIds = volumes;
}
public void updateStaste(StorageMigrationState state) {
_migrateState = state;
}
@Override
public int cleanup(CheckPointManager checkPointMgr) {
StateMachine2<Volume.State, Volume.Event, Volume> _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;
}
}