Skip to content

Commit 300c3c0

Browse files
shrikantjoshi-hpedhslove
authored andcommitted
added online/offline copy method for Primera storage adapter (apache#11298)
1 parent c020150 commit 300c3c0

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/adapter/ProviderAdapter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ public interface ProviderAdapter {
8787

8888
/**
8989
* Copy a source object to a destination volume. The source object can be a Volume, Snapshot, or Template
90+
* @param newSize the desired size in bytes for the destination volume (supports resize-during-copy)
9091
*/
91-
public ProviderVolume copy(ProviderAdapterContext context, ProviderAdapterDataObject sourceVolume, ProviderAdapterDataObject targetVolume);
92+
public ProviderVolume copy(ProviderAdapterContext context, ProviderAdapterDataObject sourceVolume, ProviderAdapterDataObject targetVolume, Long newSize);
9293

9394
/**
9495
* Make a device-specific snapshot of the provided volume

plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/driver/AdaptiveDataStoreDriverImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ public void copyAsync(DataObject srcdata, DataObject destdata,
337337
ProviderAdapterDataObject sourceIn = newManagedDataObject(srcdata, storagePool);
338338
ProviderAdapterDataObject destIn = newManagedDataObject(destdata, storagePool);
339339

340-
outVolume = api.copy(context, sourceIn, destIn);
340+
// Call provider adapter copy method with destination size parameter for resize-during-copy support
341+
outVolume = api.copy(context, sourceIn, destIn, destdata.getSize());
341342

342343
// populate this data - it may be needed later
343344
destIn.setExternalName(outVolume.getExternalName());

plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ public ProviderSnapshot getSnapshot(ProviderAdapterContext context, ProviderAdap
367367

368368
@Override
369369
public ProviderVolume copy(ProviderAdapterContext context, ProviderAdapterDataObject sourceDataObject,
370-
ProviderAdapterDataObject destDataObject) {
370+
ProviderAdapterDataObject destDataObject, Long newSize) {
371+
// Add new parameter as newSize to match method declaration but not used anywhere
371372
// private ManagedVolume copy(ManagedVolume sourceVolume, String destNamespace,
372373
// String destName) {
373374
if (sourceDataObject == null || sourceDataObject.getExternalName() == null

plugins/storage/volume/primera/src/main/java/org/apache/cloudstack/storage/datastore/adapter/primera/PrimeraAdapter.java

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,39 +288,94 @@ public void delete(ProviderAdapterContext context, ProviderAdapterDataObject req
288288

289289
@Override
290290
public ProviderVolume copy(ProviderAdapterContext context, ProviderAdapterDataObject sourceVolumeInfo,
291-
ProviderAdapterDataObject targetVolumeInfo) {
291+
ProviderAdapterDataObject targetVolumeInfo, Long newSize) {
292+
// Log the start of the copy operation with source volume details
293+
logger.debug("PrimeraAdapter: Starting volume copy operation - source volume: '{}', target volume: '{}', requested new size: {} bytes ({} MiB)",
294+
sourceVolumeInfo.getExternalName(), targetVolumeInfo.getName(), newSize, newSize / PrimeraAdapter.BYTES_IN_MiB);
295+
296+
// Flag to determine copy method: online copy (direct clone) vs offline copy (with resize)
297+
boolean onlineCopy = true;
292298
PrimeraVolumeCopyRequest request = new PrimeraVolumeCopyRequest();
293299
PrimeraVolumeCopyRequestParameters parms = new PrimeraVolumeCopyRequestParameters();
294300

295301
assert sourceVolumeInfo.getExternalName() != null: "External provider name not provided on copy request to Primera volume provider";
296302

297-
// if we have no external name, treat it as a new volume
303+
// Generate external name for target volume if not already set
298304
if (targetVolumeInfo.getExternalName() == null) {
299305
targetVolumeInfo.setExternalName(ProviderVolumeNamer.generateObjectName(context, targetVolumeInfo));
306+
logger.debug("PrimeraAdapter: Generated external name '{}' for target volume", targetVolumeInfo.getExternalName());
300307
}
301308

302309
ProviderVolume sourceVolume = this.getVolume(context, sourceVolumeInfo);
303310
if (sourceVolume == null) {
304311
throw new RuntimeException("Source volume " + sourceVolumeInfo.getExternalUuid() + " with provider name " + sourceVolumeInfo.getExternalName() + " not found on storage provider");
305312
}
306313

314+
// Determine copy method based on size difference
315+
// Online copy: Direct clone without size change (faster, immediate)
316+
// Offline copy: Copy with potential resize (slower, requires task completion wait)
317+
Long sourceSize = sourceVolume.getAllocatedSizeInBytes();
318+
if (newSize == null || sourceSize == null || !newSize.equals(sourceSize)) {
319+
logger.debug("PrimeraAdapter: Volume size change detected (source: {} bytes, target: {} bytes) - using offline copy method",
320+
sourceSize, newSize);
321+
onlineCopy = false;
322+
} else {
323+
logger.debug("PrimeraAdapter: No size change required (both {} bytes) - using online copy method for faster cloning", newSize);
324+
}
325+
326+
// Check if target volume already exists on the storage provider
307327
ProviderVolume targetVolume = this.getVolume(context, targetVolumeInfo);
308328
if (targetVolume == null) {
309-
this.create(context, targetVolumeInfo, null, sourceVolume.getAllocatedSizeInBytes());
329+
if (!onlineCopy) {
330+
// For offline copy, pre-create the target volume with the desired size
331+
logger.debug("PrimeraAdapter: Offline copy mode - pre-creating target volume '{}' with size {} bytes",
332+
targetVolumeInfo.getName(), sourceVolume.getAllocatedSizeInBytes());
333+
this.create(context, targetVolumeInfo, null, sourceVolume.getAllocatedSizeInBytes());
334+
} else {
335+
// For online copy, the target volume will be created automatically during the clone operation
336+
logger.debug("PrimeraAdapter: Online copy mode - target volume '{}' will be created automatically during clone operation",
337+
targetVolumeInfo.getName());
338+
}
339+
} else {
340+
logger.warn("PrimeraAdapter: Target volume '{}' already exists on storage provider - proceeding with copy operation",
341+
targetVolumeInfo.getExternalName());
310342
}
311343

312344
parms.setDestVolume(targetVolumeInfo.getExternalName());
313-
parms.setOnline(false);
314-
parms.setPriority(1);
345+
if (onlineCopy) {
346+
// Online copy configuration: immediate clone with deduplication and compression
347+
parms.setOnline(true);
348+
parms.setDestCPG(cpg);
349+
parms.setTpvv(false);
350+
parms.setReduce(true);
351+
logger.debug("PrimeraAdapter: Configuring online copy - destination CPG: '{}', deduplication enabled, thin provisioning disabled", cpg);
352+
} else {
353+
// Offline copy configuration: background task with high priority
354+
parms.setOnline(false);
355+
parms.setPriority(1); // Set high priority for faster completion
356+
logger.debug("PrimeraAdapter: Configuring offline copy with high priority for target volume '{}'", targetVolumeInfo.getName());
357+
}
358+
359+
// Set request parameters and initiate the copy operation
315360
request.setParameters(parms);
316361

317362
PrimeraTaskReference taskref = POST("/volumes/" + sourceVolumeInfo.getExternalName(), request, new TypeReference<PrimeraTaskReference>() {});
318363
if (taskref == null) {
364+
logger.error("PrimeraAdapter: Failed to initiate copy operation - no task reference returned from storage provider");
319365
throw new RuntimeException("Unable to retrieve task used to copy to newly created volume");
320366
}
321367

322-
waitForTaskToComplete(taskref.getTaskid(), "copy volume " + sourceVolumeInfo.getExternalName() + " to " +
323-
targetVolumeInfo.getExternalName(), taskWaitTimeoutMs);
368+
// Handle task completion based on copy method
369+
if (!onlineCopy) {
370+
// Offline copy requires waiting for task completion
371+
logger.debug("PrimeraAdapter: Offline copy initiated - waiting for task completion (TaskID: {})", taskref.getTaskid());
372+
waitForTaskToComplete(taskref.getTaskid(), "copy volume " + sourceVolumeInfo.getExternalName() + " to " +
373+
targetVolumeInfo.getExternalName(), taskWaitTimeoutMs);
374+
logger.debug("PrimeraAdapter: Offline copy operation completed successfully");
375+
} else {
376+
// Online copy completes immediately
377+
logger.debug("PrimeraAdapter: Online copy operation completed successfully (TaskID: {})", taskref.getTaskid());
378+
}
324379

325380
return this.getVolume(context, targetVolumeInfo);
326381
}

0 commit comments

Comments
 (0)