Skip to content

Commit 82f6556

Browse files
author
Pearl Dsilva
committed
Address review comments
1 parent 452fe52 commit 82f6556

File tree

18 files changed

+143
-130
lines changed

18 files changed

+143
-130
lines changed

api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListImageStoresCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public class ListImageStoresCmd extends BaseListCmd {
5151
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ImageStoreResponse.class, description = "the ID of the storage pool")
5252
private Long id;
5353

54-
@Parameter(name = ApiConstants.READ_ONLY, type = CommandType.BOOLEAN, entityType = ImageStoreResponse.class, description = "read-only status of the image store")
54+
@Parameter(name = ApiConstants.READ_ONLY, type = CommandType.BOOLEAN, entityType = ImageStoreResponse.class, description = "read-only status of the image store", since = "4.15.0")
5555
private Boolean readonly;
5656

5757
/////////////////////////////////////////////////////

api/src/main/java/org/apache/cloudstack/api/command/admin/storage/MigrateSecondaryStorageDataCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
responseObject = MigrationResponse.class,
3838
requestHasSensitiveInfo = false,
3939
responseHasSensitiveInfo = false,
40-
since = "4.14.0",
40+
since = "4.15.0",
4141
authorized = {RoleType.Admin})
4242
public class MigrateSecondaryStorageDataCmd extends BaseAsyncCmd {
4343

44-
public static final Logger s_logger = Logger.getLogger(MigrateSecondaryStorageDataCmd.class.getName());
44+
public static final Logger LOGGER = Logger.getLogger(MigrateSecondaryStorageDataCmd.class.getName());
4545

4646
public static final String APINAME = "migrateSecondaryStorageData";
4747

api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateImageStoreCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import com.cloud.storage.ImageStore;
3131

3232
@APICommand(name = UpdateImageStoreCmd.APINAME, description = "Updates image store read-only status", responseObject = ImageStoreResponse.class, entityType = {ImageStore.class},
33-
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
33+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.15.0")
3434
public class UpdateImageStoreCmd extends BaseCmd {
3535
private static final Logger LOG = Logger.getLogger(UpdateImageStoreCmd.class.getName());
3636
public static final String APINAME = "updateImageStore";

engine/components-api/src/main/java/com/cloud/storage/StorageManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ public interface StorageManager extends StorageService {
112112
ConfigKey<Integer> PRIMARY_STORAGE_DOWNLOAD_WAIT = new ConfigKey<Integer>("Storage", Integer.class, "primary.storage.download.wait", "10800",
113113
"In second, timeout for download template to primary storage", false);
114114

115+
ConfigKey<Integer> SecStorageMaxMigrateSessions = new ConfigKey<Integer>("Advanced", Integer.class, "secstorage.max.migrate.sessions", "2",
116+
"The max number of concurrent copy command execution sessions that an SSVM can handle", true, ConfigKey.Scope.Global);
117+
115118
/**
116119
* Returns a comma separated list of tags for the specified storage pool
117120
* @param poolId

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
4444
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
4545
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
46-
import org.apache.log4j.Logger;
4746

4847
import com.cloud.host.HostVO;
4948
import com.cloud.host.Status;
@@ -82,13 +81,11 @@ public class DataMigrationUtility {
8281
@Inject
8382
SnapshotDao snapshotDao;
8483

85-
private static final Logger s_logger = Logger.getLogger(DataMigrationUtility.class);
86-
8784
/** This function verifies if the given image store comprises of data objects that are not in either the "Ready" or
8885
* "Allocated" state - in such a case, if the migration policy is complete, the migration is terminated
8986
*/
90-
private boolean filesReady(Long srcDataStoreId) {
91-
String[] validStates = new String[]{"Ready", "Allocated"};
87+
private boolean filesReadyToMigrate(Long srcDataStoreId) {
88+
String[] validStates = new String[]{"Ready", "Allocated", "Destroying", "Destroyed", "Failed"};
9289
boolean isReady = true;
9390
List<TemplateDataStoreVO> templates = templateDataStoreDao.listByStoreId(srcDataStoreId);
9491
for (TemplateDataStoreVO template : templates) {
@@ -107,7 +104,7 @@ private boolean filesReady(Long srcDataStoreId) {
107104

108105
protected void checkIfCompleteMigrationPossible(ImageStoreService.MigrationPolicy policy, Long srcDataStoreId) {
109106
if (policy == ImageStoreService.MigrationPolicy.COMPLETE) {
110-
if (!filesReady(srcDataStoreId)) {
107+
if (!filesReadyToMigrate(srcDataStoreId)) {
111108
throw new CloudRuntimeException("Complete migration failed as there are data objects which are not Ready");
112109
}
113110
}
@@ -147,9 +144,9 @@ public int compare(Map.Entry<Long, Pair<Long, Long>> e1, Map.Entry<Long, Pair<Lo
147144

148145
protected List<DataObject> getSortedValidSourcesList(DataStore srcDataStore, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChains) {
149146
List<DataObject> files = new ArrayList<>();
150-
files.addAll(getAllValidTemplates(srcDataStore));
151-
files.addAll(getAllValidSnapshotsAndChains(srcDataStore, snapshotChains));
152-
files.addAll(getAllValidVolumes(srcDataStore));
147+
files.addAll(getAllReadyTemplates(srcDataStore));
148+
files.addAll(getAllReadySnapshotsAndChains(srcDataStore, snapshotChains));
149+
files.addAll(getAllReadyVolumes(srcDataStore));
153150

154151
files = sortFilesOnSize(files, snapshotChains);
155152

@@ -168,14 +165,13 @@ public int compare(DataObject o1, DataObject o2) {
168165
if (o2 instanceof SnapshotInfo) {
169166
size2 = snapshotChains.get(o2).second();
170167
}
171-
return (int) (size2 - size1);
168+
return size2 > size1 ? 1 : -1;
172169
}
173170
});
174171
return files;
175172
}
176173

177-
// Gets list of all valid templates, i.e, templates in "Ready" state for migration
178-
protected List<DataObject> getAllValidTemplates(DataStore srcDataStore) {
174+
protected List<DataObject> getAllReadyTemplates(DataStore srcDataStore) {
179175

180176
List<DataObject> files = new LinkedList<>();
181177
List<TemplateDataStoreVO> templates = templateDataStoreDao.listByStoreId(srcDataStore.getId());
@@ -192,7 +188,7 @@ protected List<DataObject> getAllValidTemplates(DataStore srcDataStore) {
192188
* for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
193189
* are migrated to the same datastore
194190
*/
195-
protected List<DataObject> getAllValidSnapshotsAndChains(DataStore srcDataStore, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChains) {
191+
protected List<DataObject> getAllReadySnapshotsAndChains(DataStore srcDataStore, Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChains) {
196192
List<SnapshotInfo> files = new LinkedList<>();
197193
List<SnapshotDataStoreVO> snapshots = snapshotDataStoreDao.listByStoreId(srcDataStore.getId(), DataStoreRole.Image);
198194
for (SnapshotDataStoreVO snapshot : snapshots) {
@@ -219,7 +215,6 @@ protected List<DataObject> getAllValidSnapshotsAndChains(DataStore srcDataStore,
219215
return (List<DataObject>) (List<?>) files;
220216
}
221217

222-
// Finds the cumulative file size for all data objects in the chain
223218
protected Long getSizeForChain(List<SnapshotInfo> chain) {
224219
Long size = 0L;
225220
for (SnapshotInfo snapshot : chain) {
@@ -228,8 +223,8 @@ protected Long getSizeForChain(List<SnapshotInfo> chain) {
228223
return size;
229224
}
230225

231-
// Returns a list of volumes that are in "Ready" state
232-
protected List<DataObject> getAllValidVolumes(DataStore srcDataStore) {
226+
227+
protected List<DataObject> getAllReadyVolumes(DataStore srcDataStore) {
233228
List<DataObject> files = new LinkedList<>();
234229
List<VolumeDataStoreVO> volumes = volumeDataStoreDao.listByStoreId(srcDataStore.getId());
235230
for (VolumeDataStoreVO volume : volumes) {

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

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,13 @@
5656
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
5757
import org.apache.log4j.Logger;
5858

59-
import com.cloud.configuration.Config;
6059
import com.cloud.server.StatsCollector;
6160
import com.cloud.storage.DataStoreRole;
6261
import com.cloud.storage.SnapshotVO;
62+
import com.cloud.storage.StorageManager;
6363
import com.cloud.storage.StorageService;
6464
import com.cloud.storage.StorageStats;
6565
import com.cloud.storage.dao.SnapshotDao;
66-
import com.cloud.utils.NumbersUtil;
6766
import com.cloud.utils.Pair;
6867
import com.cloud.utils.StringUtils;
6968
import com.cloud.utils.component.ManagerBase;
@@ -133,7 +132,7 @@ public boolean offer(T task) {
133132

134133
@Override
135134
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
136-
numConcurrentCopyTasksPerSSVM = NumbersUtil.parseInt(configDao.getValue(Config.SecStorageMaxMigrateSessions.key()), 2);
135+
numConcurrentCopyTasksPerSSVM = StorageManager.SecStorageMaxMigrateSessions.value();
137136
return true;
138137
}
139138

@@ -144,25 +143,18 @@ public MigrationResponse migrateData(Long srcDataStoreId, List<Long> destDatasto
144143
String message = null;
145144

146145
migrationHelper.checkIfCompleteMigrationPossible(migrationPolicy, srcDataStoreId);
147-
148146
DataStore srcDatastore = dataStoreManager.getDataStore(srcDataStoreId, DataStoreRole.Image);
149147
Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChains = new HashMap<>();
150148
files = migrationHelper.getSortedValidSourcesList(srcDatastore, snapshotChains);
151149

152150
if (files.isEmpty()) {
153151
return new MigrationResponse("No files in Image store "+srcDatastore.getId()+ " to migrate", migrationPolicy.toString(), true);
154152
}
155-
156-
// Create capacity class with free and total space, maybe id of ds too and use that as the value
157153
Map<Long, Pair<Long, Long>> storageCapacities = new Hashtable<>();
158-
159154
for (Long storeId : destDatastores) {
160155
storageCapacities.put(storeId, new Pair<>(null, null));
161156
}
162157
storageCapacities.put(srcDataStoreId, new Pair<>(null, null));
163-
164-
// If the migration policy is to completely migrate data from the given source Image Store, then set it's state
165-
// to readonly
166158
if (migrationPolicy == MigrationPolicy.COMPLETE) {
167159
s_logger.debug("Setting source image store "+srcDatastore.getId()+ " to read-only");
168160
storageService.updateImageStoreStatus(srcDataStoreId, true);
@@ -172,8 +164,8 @@ public MigrationResponse migrateData(Long srcDataStoreId, List<Long> destDatasto
172164
double meanstddev = getStandardDeviation(storageCapacities);
173165
double threshold = ImageStoreImbalanceThreshold.value();
174166
MigrationResponse response = null;
175-
176-
ThreadPoolExecutor executor = new ThreadPoolExecutor(numConcurrentCopyTasksPerSSVM , numConcurrentCopyTasksPerSSVM, 30, TimeUnit.MINUTES, new MigrateBlockingQueue<>(numConcurrentCopyTasksPerSSVM));
167+
ThreadPoolExecutor executor = new ThreadPoolExecutor(numConcurrentCopyTasksPerSSVM , numConcurrentCopyTasksPerSSVM, 30,
168+
TimeUnit.MINUTES, new MigrateBlockingQueue<>(numConcurrentCopyTasksPerSSVM));
177169
Date start = new Date();
178170
if (meanstddev < threshold && migrationPolicy == MigrationPolicy.BALANCE) {
179171
s_logger.debug("mean std deviation of the image stores is below threshold, no migration required");
@@ -188,28 +180,14 @@ public MigrationResponse migrateData(Long srcDataStoreId, List<Long> destDatasto
188180
chosenFileForMigration = files.remove(0);
189181
}
190182

191-
// Choose datastore with maximum free capacity as the destination datastore for migration
192183
storageCapacities = getStorageCapacities(storageCapacities);
193184
List<Long> orderedDS = migrationHelper.sortDataStores(storageCapacities);
194185
Long destDatastoreId = orderedDS.get(0);
195186

196-
// If there aren't anymore files available for migration or no valid Image stores available for migration
197-
// end the migration process
198187
if (chosenFileForMigration == null || destDatastoreId == null || destDatastoreId == srcDatastore.getId()) {
199-
if (destDatastoreId == srcDatastore.getId() && !files.isEmpty() ) {
200-
if (migrationPolicy == MigrationPolicy.BALANCE) {
201-
s_logger.debug("Migration completed : data stores have been balanced ");
202-
message = "Image stores have been balanced";
203-
success = true;
204-
} else {
205-
message = "Files not completely migrated from "+ srcDatastore.getId() +
206-
" If you want to continue using the Image Store, please change the read-only status using 'update imagestore' command";
207-
success = false;
208-
}
209-
} else {
210-
message = "Migration completed";
211-
success = true;
212-
}
188+
Pair<String, Boolean> result = migrateCompleted(destDatastoreId, srcDatastore, files, migrationPolicy);
189+
message = result.first();
190+
success = result.second();
213191
break;
214192
}
215193

@@ -218,24 +196,8 @@ public MigrationResponse migrateData(Long srcDataStoreId, List<Long> destDatasto
218196
continue;
219197
}
220198

221-
// If there is a benefit in migration of the chosen file to the destination store, then proceed with migration
222199
if (shouldMigrate(chosenFileForMigration, srcDatastore.getId(), destDatastoreId, storageCapacities, snapshotChains, migrationPolicy)) {
223-
Long fileSize = migrationHelper.getFileSize(chosenFileForMigration, snapshotChains);
224-
storageCapacities = assumeMigrate(storageCapacities, srcDatastore.getId(), destDatastoreId, fileSize);
225-
long activeSsvms = migrationHelper.activeSSVMCount(srcDatastore);
226-
long totalJobs = activeSsvms * numConcurrentCopyTasksPerSSVM;
227-
// Increase thread pool size with increase in number of SSVMs
228-
if ( totalJobs > executor.getCorePoolSize()) {
229-
executor.setMaximumPoolSize((int) (totalJobs));
230-
executor.setCorePoolSize((int) (totalJobs));
231-
}
232-
233-
MigrateDataTask task = new MigrateDataTask(chosenFileForMigration, srcDatastore, dataStoreManager.getDataStore(destDatastoreId, DataStoreRole.Image));
234-
if (chosenFileForMigration instanceof SnapshotInfo ) {
235-
task.setSnapshotChains(snapshotChains);
236-
}
237-
futures.add((executor.submit(task)));
238-
s_logger.debug("Migration of file " + chosenFileForMigration.getId() + " is initiated");
200+
migrateAway(chosenFileForMigration, storageCapacities, snapshotChains, srcDatastore, destDatastoreId, executor, futures);
239201
} else {
240202
if (migrationPolicy == MigrationPolicy.BALANCE) {
241203
message = "Migration completed and has successfully balanced the data objects among stores: " + StringUtils.join(storageCapacities.keySet(), ",");
@@ -247,11 +209,50 @@ public MigrationResponse migrateData(Long srcDataStoreId, List<Long> destDatasto
247209
}
248210
}
249211
Date end = new Date();
250-
// Migrate snapshots created during the migration process
251212
handleSnapshotMigration(srcDataStoreId, start, end, migrationPolicy, futures, storageCapacities, executor);
252213
return handleResponse(futures, migrationPolicy, message, success);
253214
}
254215

216+
protected Pair<String, Boolean> migrateCompleted(Long destDatastoreId, DataStore srcDatastore, List<DataObject> files, MigrationPolicy migrationPolicy) {
217+
String message = "";
218+
boolean success = true;
219+
if (destDatastoreId == srcDatastore.getId() && !files.isEmpty() ) {
220+
if (migrationPolicy == MigrationPolicy.BALANCE) {
221+
s_logger.debug("Migration completed : data stores have been balanced ");
222+
message = "Image stores have been balanced";
223+
success = true;
224+
} else {
225+
message = "Files not completely migrated from "+ srcDatastore.getId() +
226+
" If you want to continue using the Image Store, please change the read-only status using 'update imagestore' command";
227+
success = false;
228+
}
229+
} else {
230+
message = "Migration completed";
231+
}
232+
return new Pair<String, Boolean>(message, success);
233+
}
234+
235+
protected void migrateAway(DataObject chosenFileForMigration, Map<Long, Pair<Long, Long>> storageCapacities,
236+
Map<DataObject, Pair<List<SnapshotInfo>, Long>> snapshotChains, DataStore srcDatastore, Long destDatastoreId, ThreadPoolExecutor executor,
237+
List<Future<AsyncCallFuture<DataObjectResult>>> futures) {
238+
Long fileSize = migrationHelper.getFileSize(chosenFileForMigration, snapshotChains);
239+
storageCapacities = assumeMigrate(storageCapacities, srcDatastore.getId(), destDatastoreId, fileSize);
240+
long activeSsvms = migrationHelper.activeSSVMCount(srcDatastore);
241+
long totalJobs = activeSsvms * numConcurrentCopyTasksPerSSVM;
242+
// Increase thread pool size with increase in number of SSVMs
243+
if ( totalJobs > executor.getCorePoolSize()) {
244+
executor.setMaximumPoolSize((int) (totalJobs));
245+
executor.setCorePoolSize((int) (totalJobs));
246+
}
247+
248+
MigrateDataTask task = new MigrateDataTask(chosenFileForMigration, srcDatastore, dataStoreManager.getDataStore(destDatastoreId, DataStoreRole.Image));
249+
if (chosenFileForMigration instanceof SnapshotInfo ) {
250+
task.setSnapshotChains(snapshotChains);
251+
}
252+
futures.add((executor.submit(task)));
253+
s_logger.debug("Migration of file " + chosenFileForMigration.getId() + " is initiated");
254+
}
255+
255256

256257

257258
private MigrationResponse handleResponse(List<Future<AsyncCallFuture<DataObjectResult>>> futures, MigrationPolicy migrationPolicy, String message, boolean success) {
@@ -271,7 +272,7 @@ private MigrationResponse handleResponse(List<Future<AsyncCallFuture<DataObjectR
271272
return new MigrationResponse(message, migrationPolicy.toString(), success);
272273
}
273274

274-
private void handleSnapshotMigration(Long srcDataStoreId, Date start, Date end, MigrationPolicy policy,
275+
private void handleSnapshotMigration(Long srcDataStoreId, Date start, Date end, MigrationPolicy policy,
275276
List<Future<AsyncCallFuture<DataObjectResult>>> futures, Map<Long, Pair<Long, Long>> storageCapacities, ThreadPoolExecutor executor) {
276277
DataStore srcDatastore = dataStoreManager.getDataStore(srcDataStoreId, DataStoreRole.Image);
277278
List<SnapshotDataStoreVO> snaps = snapshotDataStoreDao.findSnapshots(srcDataStoreId, start, end);

0 commit comments

Comments
 (0)