2828import java .util .List ;
2929import java .util .Map ;
3030import java .util .Set ;
31+ import java .util .stream .Collectors ;
3132
3233import javax .inject .Inject ;
3334
@@ -94,7 +95,7 @@ public class DataMigrationUtility {
9495 * "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete,
9596 * the migration is terminated.
9697 */
97- public boolean filesReadyToMigrate (Long srcDataStoreId , List <TemplateDataStoreVO > templates , List <SnapshotDataStoreVO > snapshots , List <VolumeDataStoreVO > volumes ) {
98+ public boolean filesReadyToMigrate (List <TemplateDataStoreVO > templates , List <SnapshotDataStoreVO > snapshots , List <VolumeDataStoreVO > volumes ) {
9899 State [] validStates = {State .Ready , State .Allocated , State .Destroying , State .Destroyed , State .Failed };
99100 boolean isReady = true ;
100101 for (TemplateDataStoreVO template : templates ) {
@@ -116,7 +117,8 @@ private boolean filesReadyToMigrate(Long srcDataStoreId) {
116117 List <TemplateDataStoreVO > templates = templateDataStoreDao .listByStoreId (srcDataStoreId );
117118 List <SnapshotDataStoreVO > snapshots = snapshotDataStoreDao .listByStoreId (srcDataStoreId , DataStoreRole .Image );
118119 List <VolumeDataStoreVO > volumes = volumeDataStoreDao .listByStoreId (srcDataStoreId );
119- return filesReadyToMigrate (srcDataStoreId , templates , snapshots , volumes );
120+
121+ return filesReadyToMigrate (templates , snapshots , volumes );
120122 }
121123
122124 protected void checkIfCompleteMigrationPossible (ImageStoreService .MigrationPolicy policy , Long srcDataStoreId ) {
@@ -165,29 +167,40 @@ public int compare(Map.Entry<Long, Pair<Long, Long>> e1, Map.Entry<Long, Pair<Lo
165167 }
166168
167169 protected List <DataObject > getSortedValidSourcesList (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ,
168- Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates , List <TemplateDataStoreVO > templates , List <SnapshotDataStoreVO > snapshots ) {
170+ Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates , List <TemplateDataStoreVO > templates , List <SnapshotDataStoreVO > snapshots , Set < Long > snapshotIdsToMigrate ) {
169171 List <DataObject > files = new ArrayList <>();
170172
171173 files .addAll (getAllReadyTemplates (srcDataStore , childTemplates , templates ));
172- files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots ));
174+ files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots , snapshotIdsToMigrate ));
173175
174176 files = sortFilesOnSize (files , snapshotChains );
175177
176178 return files ;
177179 }
178180
179181 protected List <DataObject > getSortedValidSourcesList (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ,
180- Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates ) {
182+ Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates , Set < Long > snapshotIdsToMigrate ) {
181183 List <DataObject > files = new ArrayList <>();
182184 files .addAll (getAllReadyTemplates (srcDataStore , childTemplates ));
183- files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains ));
185+ files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshotIdsToMigrate ));
184186 files .addAll (getAllReadyVolumes (srcDataStore ));
185187
186188 files = sortFilesOnSize (files , snapshotChains );
187189
188190 return files ;
189191 }
190192
193+ private List <SnapshotInfo > createKvmIncrementalSnapshotChain (SnapshotDataStoreVO snapshot ) {
194+ List <SnapshotInfo > chain = new LinkedList <>();
195+ SnapshotInfo snapshotInfo = snapshotFactory .getSnapshot (snapshot .getSnapshotId (), snapshot .getDataStoreId (), snapshot .getRole ());
196+
197+ chain .addAll (snapshotInfo .getParents ());
198+ chain .add (snapshotInfo );
199+ chain .addAll (snapshotInfo .getChildAndGrandchildren ());
200+
201+ return chain ;
202+ }
203+
191204 protected List <DataObject > sortFilesOnSize (List <DataObject > files , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ) {
192205 Collections .sort (files , new Comparator <DataObject >() {
193206 @ Override
@@ -274,9 +287,10 @@ protected boolean shouldMigrateTemplate(TemplateDataStoreVO template, VMTemplate
274287 * for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
275288 * are migrated to the same datastore
276289 */
277- protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , List <SnapshotDataStoreVO > snapshots ) {
290+ protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , List <SnapshotDataStoreVO > snapshots , Set < Long > snapshotIdsToMigrate ) {
278291 List <SnapshotInfo > files = new LinkedList <>();
279292 Set <Long > idsForMigration = new HashSet <>();
293+ Set <Long > snapshotIdsAlreadyInChain = new HashSet <>();
280294
281295 for (SnapshotDataStoreVO snapshot : snapshots ) {
282296 long snapshotId = snapshot .getSnapshotId ();
@@ -300,13 +314,22 @@ protected List<DataObject> getAllReadySnapshotsAndChains(DataStore srcDataStore,
300314 if (snapshot .getParentSnapshotId () != 0 ) {
301315 continue ; // The child snapshot will be migrated in the for loop below.
302316 }
303- SnapshotInfo snap = snapshotFactory .getSnapshot (snapshotVO .getSnapshotId (), snapshot .getDataStoreId (), snapshot .getRole ());
304- if (snap == null ) {
305- logger .debug ("Not migrating snapshot [{}] because we could not get its information." , snapshot );
306- continue ;
317+
318+ if (snapshotVO .getHypervisorType () == Hypervisor .HypervisorType .KVM && snapshot .getKvmCheckpointPath () != null && !snapshotIdsAlreadyInChain .contains (snapshotVO .getId ())) {
319+ List <SnapshotInfo > kvmIncrementalSnapshotChain = createKvmIncrementalSnapshotChain (snapshot );
320+ SnapshotInfo parent = kvmIncrementalSnapshotChain .get (0 );
321+ snapshotIdsAlreadyInChain .addAll (kvmIncrementalSnapshotChain .stream ().map (DataObject ::getId ).collect (Collectors .toSet ()));
322+ snapshotChains .put (parent , new Pair <>(kvmIncrementalSnapshotChain , getTotalChainSize (kvmIncrementalSnapshotChain .stream ().filter (snapInfo -> snapshotIdsToMigrate .contains (snapInfo .getId ())).collect (Collectors .toList ()))));
323+ files .add (parent );
324+ } else {
325+ SnapshotInfo snap = snapshotFactory .getSnapshot (snapshotVO .getSnapshotId (), snapshot .getDataStoreId (), snapshot .getRole ());
326+ if (snap == null ) {
327+ logger .debug ("Not migrating snapshot [{}] because we could not get its information." , snapshot );
328+ continue ;
329+ }
330+ files .add (snap );
331+ idsForMigration .add (snapshotId );
307332 }
308- files .add (snap );
309- idsForMigration .add (snapshotId );
310333 }
311334
312335 for (SnapshotInfo parent : files ) {
@@ -319,15 +342,16 @@ protected List<DataObject> getAllReadySnapshotsAndChains(DataStore srcDataStore,
319342 chain .addAll (children );
320343 }
321344 }
322- snapshotChains .put (parent , new Pair <>(chain , getTotalChainSize (chain )));
345+ snapshotChains .putIfAbsent (parent , new Pair <>(chain , getTotalChainSize (chain )));
323346 }
324347
325348 return (List <DataObject >) (List <?>) files ;
326349 }
327350
328- protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ) {
351+ protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , Set < Long > snapshotIdsToMigrate ) {
329352 List <SnapshotDataStoreVO > snapshots = snapshotDataStoreDao .listByStoreId (srcDataStore .getId (), DataStoreRole .Image );
330- return getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots );
353+ snapshotIdsToMigrate .addAll (snapshots .stream ().map (SnapshotDataStoreVO ::getSnapshotId ).collect (Collectors .toSet ()));
354+ return getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots , snapshotIdsToMigrate );
331355 }
332356
333357 protected Long getTotalChainSize (List <? extends DataObject > chain ) {
0 commit comments