support for data migration of incremental snaps on xen (#4395)

* support for handling incremental snaps (on DB entries) on xen

* Addressed comments

* Update NfsSecondaryStorageResource.java

adjusted space in comment/ log

Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
This commit is contained in:
Pearl Dsilva 2020-10-18 02:15:10 +05:30 committed by GitHub
parent c222d0bf60
commit 0d487fc8c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 93 additions and 40 deletions

View File

@ -36,6 +36,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.ImageStoreService; import org.apache.cloudstack.storage.ImageStoreService;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
@ -47,6 +48,7 @@ import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.Status; import com.cloud.host.Status;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.DataStoreRole; import com.cloud.storage.DataStoreRole;
import com.cloud.storage.SnapshotVO; import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateVO;
@ -79,7 +81,6 @@ public class DataMigrationUtility {
HostDao hostDao; HostDao hostDao;
@Inject @Inject
SnapshotDao snapshotDao; SnapshotDao snapshotDao;
/** /**
* This function verifies if the given image store contains data objects that are not in any of the following states: * This function verifies if the given image store contains data objects that are not in any of the following states:
* "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete, * "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete,
@ -115,7 +116,7 @@ public class DataMigrationUtility {
protected Long getFileSize(DataObject file, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChain) { protected Long getFileSize(DataObject file, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChain) {
Long size = file.getSize(); Long size = file.getSize();
Pair<List<SnapshotInfo>, Long> chain = snapshotChain.get(file); Pair<List<SnapshotInfo>, Long> chain = snapshotChain.get(file);
if (file instanceof SnapshotInfo && chain.first() != null) { if (file instanceof SnapshotInfo && chain.first() != null && !chain.first().isEmpty()) {
size = chain.second(); size = chain.second();
} }
return size; return size;
@ -178,7 +179,8 @@ public class DataMigrationUtility {
List<TemplateDataStoreVO> templates = templateDataStoreDao.listByStoreId(srcDataStore.getId()); List<TemplateDataStoreVO> templates = templateDataStoreDao.listByStoreId(srcDataStore.getId());
for (TemplateDataStoreVO template : templates) { for (TemplateDataStoreVO template : templates) {
VMTemplateVO templateVO = templateDao.findById(template.getTemplateId()); VMTemplateVO templateVO = templateDao.findById(template.getTemplateId());
if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && !templateVO.isPublicTemplate()) { if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && templateVO != null && !templateVO.isPublicTemplate() &&
templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator) {
files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore)); files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore));
} }
} }
@ -194,7 +196,9 @@ public class DataMigrationUtility {
List<SnapshotDataStoreVO> snapshots = snapshotDataStoreDao.listByStoreId(srcDataStore.getId(), DataStoreRole.Image); List<SnapshotDataStoreVO> snapshots = snapshotDataStoreDao.listByStoreId(srcDataStore.getId(), DataStoreRole.Image);
for (SnapshotDataStoreVO snapshot : snapshots) { for (SnapshotDataStoreVO snapshot : snapshots) {
SnapshotVO snapshotVO = snapshotDao.findById(snapshot.getSnapshotId()); SnapshotVO snapshotVO = snapshotDao.findById(snapshot.getSnapshotId());
if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready && snapshot.getParentSnapshotId() == 0 ) { if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready &&
snapshotVO != null && snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator
&& snapshot.getParentSnapshotId() == 0 ) {
SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image); SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image);
files.add(snap); files.add(snap);
} }
@ -230,7 +234,10 @@ public class DataMigrationUtility {
List<VolumeDataStoreVO> volumes = volumeDataStoreDao.listByStoreId(srcDataStore.getId()); List<VolumeDataStoreVO> volumes = volumeDataStoreDao.listByStoreId(srcDataStore.getId());
for (VolumeDataStoreVO volume : volumes) { for (VolumeDataStoreVO volume : volumes) {
if (volume.getState() == ObjectInDataStoreStateMachine.State.Ready) { if (volume.getState() == ObjectInDataStoreStateMachine.State.Ready) {
files.add(volumeFactory.getVolume(volume.getVolumeId(), srcDataStore)); VolumeInfo volumeInfo = volumeFactory.getVolume(volume.getVolumeId(), srcDataStore);
if (volumeInfo != null && volumeInfo.getHypervisorType() != Hypervisor.HypervisorType.Simulator) {
files.add(volumeInfo);
}
} }
} }
return files; return files;

View File

@ -393,7 +393,6 @@ public class StorageOrchestrator extends ManagerBase implements StorageOrchestra
if (meanStdDevCurrent > threshold && storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) { if (meanStdDevCurrent > threshold && storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) {
return true; return true;
} }
return true;
} else { } else {
if (storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) { if (storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) {
return true; return true;
@ -404,7 +403,8 @@ public class StorageOrchestrator extends ManagerBase implements StorageOrchestra
private boolean storageCapacityBelowThreshold(Map<Long, Pair<Long, Long>> storageCapacities, Long destStoreId) { private boolean storageCapacityBelowThreshold(Map<Long, Pair<Long, Long>> storageCapacities, Long destStoreId) {
Pair<Long, Long> imageStoreCapacity = storageCapacities.get(destStoreId); Pair<Long, Long> imageStoreCapacity = storageCapacities.get(destStoreId);
if (imageStoreCapacity != null && (imageStoreCapacity.first() / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) { long usedCapacity = imageStoreCapacity.second() - imageStoreCapacity.first();
if (imageStoreCapacity != null && (usedCapacity / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) {
s_logger.debug("image store: " + destStoreId + " has sufficient capacity to proceed with migration of file"); s_logger.debug("image store: " + destStoreId + " has sufficient capacity to proceed with migration of file");
return true; return true;
} }

View File

@ -291,4 +291,8 @@ public class SnapshotDataStoreVO implements StateObject<ObjectInDataStoreStateMa
public void setVolumeId(Long volumeId) { public void setVolumeId(Long volumeId) {
this.volumeId = volumeId; this.volumeId = volumeId;
} }
public void setCreated(Date created) {
this.created = created;
}
} }

View File

@ -402,4 +402,7 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
this.extractUrlCreated = extractUrlCreated; this.extractUrlCreated = extractUrlCreated;
} }
public void setCreated(Date created) {
this.created = created;
}
} }

View File

@ -381,4 +381,8 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
public void setExtractUrlCreated(Date extractUrlCreated) { public void setExtractUrlCreated(Date extractUrlCreated) {
this.extractUrlCreated = extractUrlCreated; this.extractUrlCreated = extractUrlCreated;
} }
public void setCreated(Date created) {
this.created = created;
}
} }

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.storage.image; package org.apache.cloudstack.storage.image;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -88,11 +89,29 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
DataObject destDataObject = null; DataObject destDataObject = null;
try { try {
if (srcDataObject instanceof SnapshotInfo && snapshotChain != null && snapshotChain.containsKey(srcDataObject)) { if (srcDataObject instanceof SnapshotInfo && snapshotChain != null && snapshotChain.containsKey(srcDataObject)) {
List<String> parentSnapshotPaths = new ArrayList<>();
for (SnapshotInfo snapshotInfo : snapshotChain.get(srcDataObject).first()) { for (SnapshotInfo snapshotInfo : snapshotChain.get(srcDataObject).first()) {
if (!parentSnapshotPaths.isEmpty() && parentSnapshotPaths.contains(snapshotInfo.getPath())) {
parentSnapshotPaths.add(snapshotInfo.getPath());
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findByStoreSnapshot(DataStoreRole.Image, srcDatastore.getId(), snapshotInfo.getSnapshotId());
if (snapshotStore == null) {
res.setResult("Failed to find snapshot " + snapshotInfo.getUuid() + " on store: " + srcDatastore.getName());
res.setSuccess(false);
future.complete(res);
break;
}
snapshotStore.setDataStoreId(destDatastore.getId());
snapshotStoreDao.update(snapshotStore.getId(), snapshotStore);
continue;
}
parentSnapshotPaths.add(snapshotInfo.getPath());
destDataObject = destDatastore.create(snapshotInfo); destDataObject = destDatastore.create(snapshotInfo);
snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested); snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested); destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
migrateJob(future, snapshotInfo, destDataObject, destDatastore); migrateJob(future, snapshotInfo, destDataObject, destDatastore);
if (future.get() != null && future.get().isFailed()) {
break;
}
} }
} else { } else {
// Check if template in destination store, if yes, do not proceed // Check if template in destination store, if yes, do not proceed
@ -163,26 +182,13 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
if (destData != null) { if (destData != null) {
destData.getDataStore().delete(destData); destData.getDataStore().delete(destData);
} }
} else { } else {
if (destData instanceof VolumeInfo) { if (destData instanceof VolumeInfo) {
((VolumeInfo) destData).processEventOnly(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer); ((VolumeInfo) destData).processEventOnly(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer);
} else { } else {
destData.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer); destData.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer);
} }
if (destData instanceof SnapshotInfo) { updateDataObject(srcData, destData);
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySourceSnapshot(srcData.getId(), DataStoreRole.Image);
SnapshotDataStoreVO destSnapshotStore = snapshotStoreDao.findBySnapshot(srcData.getId(), DataStoreRole.Image);
destSnapshotStore.setPhysicalSize(snapshotStore.getPhysicalSize());
snapshotStoreDao.update(destSnapshotStore.getId(), destSnapshotStore);
}
if (destData instanceof VolumeInfo) {
VolumeDataStoreVO srcVolume = volumeDataStoreDao.findByStoreVolume(srcData.getDataStore().getId(), srcData.getId());
VolumeDataStoreVO destVolume = volumeDataStoreDao.findByStoreVolume(destData.getDataStore().getId(), destData.getId());
destVolume.setPhysicalSize(srcVolume.getPhysicalSize());
volumeDataStoreDao.update(destVolume.getId(), destVolume);
}
s_logger.debug("Deleting source data"); s_logger.debug("Deleting source data");
srcData.getDataStore().delete(srcData); srcData.getDataStore().delete(srcData);
s_logger.debug("Successfully migrated "+srcData.getUuid()); s_logger.debug("Successfully migrated "+srcData.getUuid());
@ -198,6 +204,37 @@ public class SecondaryStorageServiceImpl implements SecondaryStorageService {
return null; return null;
} }
private void updateDataObject(DataObject srcData, DataObject destData) {
if (destData instanceof SnapshotInfo) {
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySourceSnapshot(srcData.getId(), DataStoreRole.Image);
SnapshotDataStoreVO destSnapshotStore = snapshotStoreDao.findBySnapshot(srcData.getId(), DataStoreRole.Image);
if (snapshotStore != null && destSnapshotStore != null) {
destSnapshotStore.setPhysicalSize(snapshotStore.getPhysicalSize());
destSnapshotStore.setCreated(snapshotStore.getCreated());
if (snapshotStore.getParentSnapshotId() != destSnapshotStore.getParentSnapshotId()) {
destSnapshotStore.setParentSnapshotId(snapshotStore.getParentSnapshotId());
}
snapshotStoreDao.update(destSnapshotStore.getId(), destSnapshotStore);
}
} else if (destData instanceof VolumeInfo) {
VolumeDataStoreVO srcVolume = volumeDataStoreDao.findByStoreVolume(srcData.getDataStore().getId(), srcData.getId());
VolumeDataStoreVO destVolume = volumeDataStoreDao.findByStoreVolume(destData.getDataStore().getId(), destData.getId());
if (srcVolume != null && destVolume != null) {
destVolume.setPhysicalSize(srcVolume.getPhysicalSize());
destVolume.setCreated(srcVolume.getCreated());
volumeDataStoreDao.update(destVolume.getId(), destVolume);
}
} else if (destData instanceof TemplateInfo) {
TemplateDataStoreVO srcTemplate = templateStoreDao.findByStoreTemplate(srcData.getDataStore().getId(), srcData.getId());
TemplateDataStoreVO destTemplate = templateStoreDao.findByStoreTemplate(destData.getDataStore().getId(), destData.getId());
if (srcTemplate != null && destTemplate != null) {
destTemplate.setCreated(srcTemplate.getCreated());
templateStoreDao.update(destTemplate.getId(), destTemplate);
}
} else {
s_logger.debug("Unsupported data object type");
}
}
} }

View File

@ -391,17 +391,18 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
private Answer sendToLeastBusyEndpoint(List<EndPoint> eps, CopyCommand cmd) { private Answer sendToLeastBusyEndpoint(List<EndPoint> eps, CopyCommand cmd) {
Answer answer = null; Answer answer = null;
EndPoint endPoint = null; EndPoint endPoint = null;
Long epId = ssvmWithLeastMigrateJobs(); List<Long> epIds = ssvmWithLeastMigrateJobs();
if (epId == null) {
if (epIds.isEmpty()) {
Collections.shuffle(eps); Collections.shuffle(eps);
endPoint = eps.get(0); endPoint = eps.get(0);
} else { } else {
List<EndPoint> remainingEps = eps.stream().filter(ep -> ep.getId() != epId ).collect(Collectors.toList()); List<EndPoint> remainingEps = eps.stream().filter(ep -> !epIds.contains(ep.getId())).collect(Collectors.toList());
if (!remainingEps.isEmpty()) { if (!remainingEps.isEmpty()) {
Collections.shuffle(remainingEps); Collections.shuffle(remainingEps);
endPoint = remainingEps.get(0); endPoint = remainingEps.get(0);
} else { } else {
endPoint = _defaultEpSelector.getEndPointFromHostId(epId); endPoint = _defaultEpSelector.getEndPointFromHostId(epIds.get(0));
} }
} }
CommandExecLogVO execLog = new CommandExecLogVO(endPoint.getId(), _secStorageVmDao.findByInstanceName(hostDao.findById(endPoint.getId()).getName()).getId(), "DataMigrationCommand", 1); CommandExecLogVO execLog = new CommandExecLogVO(endPoint.getId(), _secStorageVmDao.findByInstanceName(hostDao.findById(endPoint.getId()).getName()).getId(), "DataMigrationCommand", 1);
@ -495,27 +496,22 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
return null; return null;
} }
private Integer getCopyCmdsCountToSpecificSSVM(Long ssvmId) { private List<Long> ssvmWithLeastMigrateJobs() {
return _cmdExecLogDao.getCopyCmdCountForSSVM(ssvmId);
}
private Long ssvmWithLeastMigrateJobs() {
s_logger.debug("Picking ssvm from the pool with least commands running on it"); s_logger.debug("Picking ssvm from the pool with least commands running on it");
String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2 limit 1;"; String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2;";
TransactionLegacy txn = TransactionLegacy.currentTxn(); TransactionLegacy txn = TransactionLegacy.currentTxn();
Long epId = null; List<Long> result = new ArrayList<Long>();
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
pstmt = txn.prepareAutoCloseStatement(query); pstmt = txn.prepareAutoCloseStatement(query);
ResultSet rs = pstmt.executeQuery(); ResultSet rs = pstmt.executeQuery();
if (rs.getFetchSize() > 0) { while (rs.next()) {
rs.absolute(1); result.add((long) rs.getInt(1));
epId = (long) rs.getInt(1);
} }
} catch (SQLException e) { } catch (SQLException e) {
s_logger.debug("SQLException caught", e); s_logger.debug("SQLException caught", e);
} }
return epId; return result;
} }
} }

View File

@ -191,7 +191,7 @@ public class PremiumSecondaryStorageManagerImpl extends SecondaryStorageManagerI
private void scaleDownSSVMOnLoad(List<SecondaryStorageVmVO> alreadyRunning, List<CommandExecLogVO> activeCmds, private void scaleDownSSVMOnLoad(List<SecondaryStorageVmVO> alreadyRunning, List<CommandExecLogVO> activeCmds,
List<CommandExecLogVO> copyCmdsInPipeline) { List<CommandExecLogVO> copyCmdsInPipeline) {
int halfLimit = Math.round((float) (alreadyRunning.size() * migrateCapPerSSVM) / 2); int halfLimit = Math.round((float) (alreadyRunning.size() * migrateCapPerSSVM) / 2);
if ((copyCmdsInPipeline.size() < halfLimit && alreadyRunning.size() * _capacityPerSSVM - activeCmds.size() > (_standbyCapacity + 5)) && alreadyRunning.size() > 1) { if (alreadyRunning.size() > 1 && ( copyCmdsInPipeline.size() < halfLimit && (activeCmds.size() < (((alreadyRunning.size() -1) * _capacityPerSSVM)/2)) )) {
Collections.reverse(alreadyRunning); Collections.reverse(alreadyRunning);
for(SecondaryStorageVmVO vm : alreadyRunning) { for(SecondaryStorageVmVO vm : alreadyRunning) {
long count = activeCmds.stream().filter(cmd -> cmd.getInstanceId() == vm.getId()).count(); long count = activeCmds.stream().filter(cmd -> cmd.getInstanceId() == vm.getId()).count();

View File

@ -1300,15 +1300,17 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
try { try {
File srcFile = new File(getDir(srcStore.getUrl(), _nfsVersion), srcData.getPath()); File srcFile = new File(getDir(srcStore.getUrl(), _nfsVersion), srcData.getPath());
File destFile = new File(getDir(destStore.getUrl(), _nfsVersion), destData.getPath()); File destFile = new File(getDir(destStore.getUrl(), _nfsVersion), destData.getPath());
ImageFormat format = getTemplateFormat(srcFile.getName());
if (srcFile == null) { if (srcFile == null) {
return new CopyCmdAnswer("Can't find src file:" + srcFile); return new CopyCmdAnswer("Can't find source file at path: "+ srcData.getPath() +" on datastore: "+ srcDataStore.getUuid() +" to initiate file transfer");
} }
ImageFormat format = getTemplateFormat(srcFile.getName());
if (srcData instanceof TemplateObjectTO || srcData instanceof VolumeObjectTO) { if (srcData instanceof TemplateObjectTO || srcData instanceof VolumeObjectTO) {
File srcDir = null; File srcDir = null;
if (srcFile.isFile() || srcFile.getName().contains(".")) { if (srcFile.isFile() || srcFile.getName().contains(".")) {
srcDir = new File(srcFile.getParent()); srcDir = new File(srcFile.getParent());
} else if (!srcFile.isDirectory()) {
srcDir = new File(srcFile.getParent());
} }
File destDir = null; File destDir = null;
if (destFile.isFile()) { if (destFile.isFile()) {
@ -1351,7 +1353,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
if (srcFile.isFile()) { if (srcFile.isFile()) {
newVol.setPath(destData.getPath() + File.separator + srcFile.getName()); newVol.setPath(destData.getPath() + File.separator + srcFile.getName());
} else { } else {
newVol.setPath(destData.getPath()); newVol.setPath(srcData.getPath());
} }
newVol.setSize(getVirtualSize(srcFile, format)); newVol.setSize(getVirtualSize(srcFile, format));
retObj = newVol; retObj = newVol;