Skip to content

Commit 0d487fc

Browse files
Pearl1594Pearl Dsilva
andauthored
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>
1 parent c222d0b commit 0d487fc

9 files changed

Lines changed: 93 additions & 40 deletions

File tree

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/DataMigrationUtility.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
3737
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
3838
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
39+
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
3940
import org.apache.cloudstack.storage.ImageStoreService;
4041
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
4142
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
@@ -47,6 +48,7 @@
4748
import com.cloud.host.HostVO;
4849
import com.cloud.host.Status;
4950
import com.cloud.host.dao.HostDao;
51+
import com.cloud.hypervisor.Hypervisor;
5052
import com.cloud.storage.DataStoreRole;
5153
import com.cloud.storage.SnapshotVO;
5254
import com.cloud.storage.VMTemplateVO;
@@ -79,7 +81,6 @@ public class DataMigrationUtility {
7981
HostDao hostDao;
8082
@Inject
8183
SnapshotDao snapshotDao;
82-
8384
/**
8485
* This function verifies if the given image store contains data objects that are not in any of the following states:
8586
* "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete,
@@ -115,7 +116,7 @@ protected void checkIfCompleteMigrationPossible(ImageStoreService.MigrationPolic
115116
protected Long getFileSize(DataObject file, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChain) {
116117
Long size = file.getSize();
117118
Pair<List<SnapshotInfo>, Long> chain = snapshotChain.get(file);
118-
if (file instanceof SnapshotInfo && chain.first() != null) {
119+
if (file instanceof SnapshotInfo && chain.first() != null && !chain.first().isEmpty()) {
119120
size = chain.second();
120121
}
121122
return size;
@@ -178,7 +179,8 @@ protected List<DataObject> getAllReadyTemplates(DataStore srcDataStore) {
178179
List<TemplateDataStoreVO> templates = templateDataStoreDao.listByStoreId(srcDataStore.getId());
179180
for (TemplateDataStoreVO template : templates) {
180181
VMTemplateVO templateVO = templateDao.findById(template.getTemplateId());
181-
if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && !templateVO.isPublicTemplate()) {
182+
if (template.getState() == ObjectInDataStoreStateMachine.State.Ready && templateVO != null && !templateVO.isPublicTemplate() &&
183+
templateVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator) {
182184
files.add(templateFactory.getTemplate(template.getTemplateId(), srcDataStore));
183185
}
184186
}
@@ -194,7 +196,9 @@ protected List<DataObject> getAllReadySnapshotsAndChains(DataStore srcDataStore,
194196
List<SnapshotDataStoreVO> snapshots = snapshotDataStoreDao.listByStoreId(srcDataStore.getId(), DataStoreRole.Image);
195197
for (SnapshotDataStoreVO snapshot : snapshots) {
196198
SnapshotVO snapshotVO = snapshotDao.findById(snapshot.getSnapshotId());
197-
if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready && snapshot.getParentSnapshotId() == 0 ) {
199+
if (snapshot.getState() == ObjectInDataStoreStateMachine.State.Ready &&
200+
snapshotVO != null && snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator
201+
&& snapshot.getParentSnapshotId() == 0 ) {
198202
SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image);
199203
files.add(snap);
200204
}
@@ -230,7 +234,10 @@ protected List<DataObject> getAllReadyVolumes(DataStore srcDataStore) {
230234
List<VolumeDataStoreVO> volumes = volumeDataStoreDao.listByStoreId(srcDataStore.getId());
231235
for (VolumeDataStoreVO volume : volumes) {
232236
if (volume.getState() == ObjectInDataStoreStateMachine.State.Ready) {
233-
files.add(volumeFactory.getVolume(volume.getVolumeId(), srcDataStore));
237+
VolumeInfo volumeInfo = volumeFactory.getVolume(volume.getVolumeId(), srcDataStore);
238+
if (volumeInfo != null && volumeInfo.getHypervisorType() != Hypervisor.HypervisorType.Simulator) {
239+
files.add(volumeInfo);
240+
}
234241
}
235242
}
236243
return files;

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,6 @@ private boolean shouldMigrate(DataObject chosenFile, Long srcDatastoreId, Long d
393393
if (meanStdDevCurrent > threshold && storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) {
394394
return true;
395395
}
396-
return true;
397396
} else {
398397
if (storageCapacityBelowThreshold(storageCapacities, destDatastoreId)) {
399398
return true;
@@ -404,7 +403,8 @@ private boolean shouldMigrate(DataObject chosenFile, Long srcDatastoreId, Long d
404403

405404
private boolean storageCapacityBelowThreshold(Map<Long, Pair<Long, Long>> storageCapacities, Long destStoreId) {
406405
Pair<Long, Long> imageStoreCapacity = storageCapacities.get(destStoreId);
407-
if (imageStoreCapacity != null && (imageStoreCapacity.first() / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) {
406+
long usedCapacity = imageStoreCapacity.second() - imageStoreCapacity.first();
407+
if (imageStoreCapacity != null && (usedCapacity / (imageStoreCapacity.second() * 1.0)) <= imageStoreCapacityThreshold) {
408408
s_logger.debug("image store: " + destStoreId + " has sufficient capacity to proceed with migration of file");
409409
return true;
410410
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreVO.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,8 @@ public Long getVolumeId() {
291291
public void setVolumeId(Long volumeId) {
292292
this.volumeId = volumeId;
293293
}
294+
295+
public void setCreated(Date created) {
296+
this.created = created;
297+
}
294298
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,7 @@ public void setExtractUrlCreated(Date extractUrlCreated) {
402402
this.extractUrlCreated = extractUrlCreated;
403403
}
404404

405+
public void setCreated(Date created) {
406+
this.created = created;
407+
}
405408
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,8 @@ public Date getExtractUrlCreated() {
381381
public void setExtractUrlCreated(Date extractUrlCreated) {
382382
this.extractUrlCreated = extractUrlCreated;
383383
}
384+
385+
public void setCreated(Date created) {
386+
this.created = created;
387+
}
384388
}

engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/SecondaryStorageServiceImpl.java

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.cloudstack.storage.image;
1919

20+
import java.util.ArrayList;
2021
import java.util.List;
2122
import java.util.Map;
2223
import java.util.concurrent.ExecutionException;
@@ -88,11 +89,29 @@ public AsyncCallFuture<DataObjectResult> migrateData(DataObject srcDataObject, D
8889
DataObject destDataObject = null;
8990
try {
9091
if (srcDataObject instanceof SnapshotInfo && snapshotChain != null && snapshotChain.containsKey(srcDataObject)) {
92+
List<String> parentSnapshotPaths = new ArrayList<>();
9193
for (SnapshotInfo snapshotInfo : snapshotChain.get(srcDataObject).first()) {
94+
if (!parentSnapshotPaths.isEmpty() && parentSnapshotPaths.contains(snapshotInfo.getPath())) {
95+
parentSnapshotPaths.add(snapshotInfo.getPath());
96+
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findByStoreSnapshot(DataStoreRole.Image, srcDatastore.getId(), snapshotInfo.getSnapshotId());
97+
if (snapshotStore == null) {
98+
res.setResult("Failed to find snapshot " + snapshotInfo.getUuid() + " on store: " + srcDatastore.getName());
99+
res.setSuccess(false);
100+
future.complete(res);
101+
break;
102+
}
103+
snapshotStore.setDataStoreId(destDatastore.getId());
104+
snapshotStoreDao.update(snapshotStore.getId(), snapshotStore);
105+
continue;
106+
}
107+
parentSnapshotPaths.add(snapshotInfo.getPath());
92108
destDataObject = destDatastore.create(snapshotInfo);
93109
snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
94110
destDataObject.processEvent(ObjectInDataStoreStateMachine.Event.MigrateDataRequested);
95111
migrateJob(future, snapshotInfo, destDataObject, destDatastore);
112+
if (future.get() != null && future.get().isFailed()) {
113+
break;
114+
}
96115
}
97116
} else {
98117
// Check if template in destination store, if yes, do not proceed
@@ -163,26 +182,13 @@ protected Void migrateDataCallBack(AsyncCallbackDispatcher<SecondaryStorageServi
163182
if (destData != null) {
164183
destData.getDataStore().delete(destData);
165184
}
166-
167185
} else {
168186
if (destData instanceof VolumeInfo) {
169187
((VolumeInfo) destData).processEventOnly(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer);
170188
} else {
171189
destData.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed, answer);
172190
}
173-
if (destData instanceof SnapshotInfo) {
174-
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySourceSnapshot(srcData.getId(), DataStoreRole.Image);
175-
SnapshotDataStoreVO destSnapshotStore = snapshotStoreDao.findBySnapshot(srcData.getId(), DataStoreRole.Image);
176-
destSnapshotStore.setPhysicalSize(snapshotStore.getPhysicalSize());
177-
snapshotStoreDao.update(destSnapshotStore.getId(), destSnapshotStore);
178-
}
179-
180-
if (destData instanceof VolumeInfo) {
181-
VolumeDataStoreVO srcVolume = volumeDataStoreDao.findByStoreVolume(srcData.getDataStore().getId(), srcData.getId());
182-
VolumeDataStoreVO destVolume = volumeDataStoreDao.findByStoreVolume(destData.getDataStore().getId(), destData.getId());
183-
destVolume.setPhysicalSize(srcVolume.getPhysicalSize());
184-
volumeDataStoreDao.update(destVolume.getId(), destVolume);
185-
}
191+
updateDataObject(srcData, destData);
186192
s_logger.debug("Deleting source data");
187193
srcData.getDataStore().delete(srcData);
188194
s_logger.debug("Successfully migrated "+srcData.getUuid());
@@ -198,6 +204,37 @@ protected Void migrateDataCallBack(AsyncCallbackDispatcher<SecondaryStorageServi
198204
return null;
199205
}
200206

207+
private void updateDataObject(DataObject srcData, DataObject destData) {
208+
if (destData instanceof SnapshotInfo) {
209+
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySourceSnapshot(srcData.getId(), DataStoreRole.Image);
210+
SnapshotDataStoreVO destSnapshotStore = snapshotStoreDao.findBySnapshot(srcData.getId(), DataStoreRole.Image);
211+
if (snapshotStore != null && destSnapshotStore != null) {
212+
destSnapshotStore.setPhysicalSize(snapshotStore.getPhysicalSize());
213+
destSnapshotStore.setCreated(snapshotStore.getCreated());
214+
if (snapshotStore.getParentSnapshotId() != destSnapshotStore.getParentSnapshotId()) {
215+
destSnapshotStore.setParentSnapshotId(snapshotStore.getParentSnapshotId());
216+
}
217+
snapshotStoreDao.update(destSnapshotStore.getId(), destSnapshotStore);
218+
}
219+
} else if (destData instanceof VolumeInfo) {
220+
VolumeDataStoreVO srcVolume = volumeDataStoreDao.findByStoreVolume(srcData.getDataStore().getId(), srcData.getId());
221+
VolumeDataStoreVO destVolume = volumeDataStoreDao.findByStoreVolume(destData.getDataStore().getId(), destData.getId());
222+
if (srcVolume != null && destVolume != null) {
223+
destVolume.setPhysicalSize(srcVolume.getPhysicalSize());
224+
destVolume.setCreated(srcVolume.getCreated());
225+
volumeDataStoreDao.update(destVolume.getId(), destVolume);
226+
}
227+
} else if (destData instanceof TemplateInfo) {
228+
TemplateDataStoreVO srcTemplate = templateStoreDao.findByStoreTemplate(srcData.getDataStore().getId(), srcData.getId());
229+
TemplateDataStoreVO destTemplate = templateStoreDao.findByStoreTemplate(destData.getDataStore().getId(), destData.getId());
230+
if (srcTemplate != null && destTemplate != null) {
231+
destTemplate.setCreated(srcTemplate.getCreated());
232+
templateStoreDao.update(destTemplate.getId(), destTemplate);
233+
}
234+
} else {
235+
s_logger.debug("Unsupported data object type");
236+
}
237+
}
201238
}
202239

203240

engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,18 @@ public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCa
391391
private Answer sendToLeastBusyEndpoint(List<EndPoint> eps, CopyCommand cmd) {
392392
Answer answer = null;
393393
EndPoint endPoint = null;
394-
Long epId = ssvmWithLeastMigrateJobs();
395-
if (epId == null) {
394+
List<Long> epIds = ssvmWithLeastMigrateJobs();
395+
396+
if (epIds.isEmpty()) {
396397
Collections.shuffle(eps);
397398
endPoint = eps.get(0);
398399
} else {
399-
List<EndPoint> remainingEps = eps.stream().filter(ep -> ep.getId() != epId ).collect(Collectors.toList());
400+
List<EndPoint> remainingEps = eps.stream().filter(ep -> !epIds.contains(ep.getId())).collect(Collectors.toList());
400401
if (!remainingEps.isEmpty()) {
401402
Collections.shuffle(remainingEps);
402403
endPoint = remainingEps.get(0);
403404
} else {
404-
endPoint = _defaultEpSelector.getEndPointFromHostId(epId);
405+
endPoint = _defaultEpSelector.getEndPointFromHostId(epIds.get(0));
405406
}
406407
}
407408
CommandExecLogVO execLog = new CommandExecLogVO(endPoint.getId(), _secStorageVmDao.findByInstanceName(hostDao.findById(endPoint.getId()).getName()).getId(), "DataMigrationCommand", 1);
@@ -495,27 +496,22 @@ public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String pa
495496
return null;
496497
}
497498

498-
private Integer getCopyCmdsCountToSpecificSSVM(Long ssvmId) {
499-
return _cmdExecLogDao.getCopyCmdCountForSSVM(ssvmId);
500-
}
501-
502-
private Long ssvmWithLeastMigrateJobs() {
499+
private List<Long> ssvmWithLeastMigrateJobs() {
503500
s_logger.debug("Picking ssvm from the pool with least commands running on it");
504-
String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2 limit 1;";
501+
String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2;";
505502
TransactionLegacy txn = TransactionLegacy.currentTxn();
506503

507-
Long epId = null;
504+
List<Long> result = new ArrayList<Long>();
508505
PreparedStatement pstmt = null;
509506
try {
510507
pstmt = txn.prepareAutoCloseStatement(query);
511508
ResultSet rs = pstmt.executeQuery();
512-
if (rs.getFetchSize() > 0) {
513-
rs.absolute(1);
514-
epId = (long) rs.getInt(1);
509+
while (rs.next()) {
510+
result.add((long) rs.getInt(1));
515511
}
516512
} catch (SQLException e) {
517513
s_logger.debug("SQLException caught", e);
518514
}
519-
return epId;
515+
return result;
520516
}
521517
}

services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/PremiumSecondaryStorageManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ else if (!copyCmdsInPipeline.isEmpty() && copyCmdsInPipeline.size() >= halfLimi
191191
private void scaleDownSSVMOnLoad(List<SecondaryStorageVmVO> alreadyRunning, List<CommandExecLogVO> activeCmds,
192192
List<CommandExecLogVO> copyCmdsInPipeline) {
193193
int halfLimit = Math.round((float) (alreadyRunning.size() * migrateCapPerSSVM) / 2);
194-
if ((copyCmdsInPipeline.size() < halfLimit && alreadyRunning.size() * _capacityPerSSVM - activeCmds.size() > (_standbyCapacity + 5)) && alreadyRunning.size() > 1) {
194+
if (alreadyRunning.size() > 1 && ( copyCmdsInPipeline.size() < halfLimit && (activeCmds.size() < (((alreadyRunning.size() -1) * _capacityPerSSVM)/2)) )) {
195195
Collections.reverse(alreadyRunning);
196196
for(SecondaryStorageVmVO vm : alreadyRunning) {
197197
long count = activeCmds.stream().filter(cmd -> cmd.getInstanceId() == vm.getId()).count();

services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,15 +1300,17 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) {
13001300
try {
13011301
File srcFile = new File(getDir(srcStore.getUrl(), _nfsVersion), srcData.getPath());
13021302
File destFile = new File(getDir(destStore.getUrl(), _nfsVersion), destData.getPath());
1303-
ImageFormat format = getTemplateFormat(srcFile.getName());
13041303

13051304
if (srcFile == null) {
1306-
return new CopyCmdAnswer("Can't find src file:" + srcFile);
1305+
return new CopyCmdAnswer("Can't find source file at path: "+ srcData.getPath() +" on datastore: "+ srcDataStore.getUuid() +" to initiate file transfer");
13071306
}
1307+
ImageFormat format = getTemplateFormat(srcFile.getName());
13081308
if (srcData instanceof TemplateObjectTO || srcData instanceof VolumeObjectTO) {
13091309
File srcDir = null;
13101310
if (srcFile.isFile() || srcFile.getName().contains(".")) {
13111311
srcDir = new File(srcFile.getParent());
1312+
} else if (!srcFile.isDirectory()) {
1313+
srcDir = new File(srcFile.getParent());
13121314
}
13131315
File destDir = null;
13141316
if (destFile.isFile()) {
@@ -1351,7 +1353,7 @@ protected Answer copyFromNfsToNfs(CopyCommand cmd) {
13511353
if (srcFile.isFile()) {
13521354
newVol.setPath(destData.getPath() + File.separator + srcFile.getName());
13531355
} else {
1354-
newVol.setPath(destData.getPath());
1356+
newVol.setPath(srcData.getPath());
13551357
}
13561358
newVol.setSize(getVirtualSize(srcFile, format));
13571359
retObj = newVol;

0 commit comments

Comments
 (0)