2222import java .util .Collections ;
2323import java .util .Comparator ;
2424import java .util .HashMap ;
25+ import java .util .HashSet ;
2526import java .util .LinkedHashMap ;
2627import java .util .LinkedList ;
2728import java .util .List ;
2829import java .util .Map ;
30+ import java .util .Set ;
31+ import java .util .stream .Collectors ;
2932
3033import javax .inject .Inject ;
3134
@@ -92,7 +95,7 @@ public class DataMigrationUtility {
9295 * "Ready" "Allocated", "Destroying", "Destroyed", "Failed". If this is the case, and if the migration policy is complete,
9396 * the migration is terminated.
9497 */
95- 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 ) {
9699 State [] validStates = {State .Ready , State .Allocated , State .Destroying , State .Destroyed , State .Failed };
97100 boolean isReady = true ;
98101 for (TemplateDataStoreVO template : templates ) {
@@ -114,7 +117,8 @@ private boolean filesReadyToMigrate(Long srcDataStoreId) {
114117 List <TemplateDataStoreVO > templates = templateDataStoreDao .listByStoreId (srcDataStoreId );
115118 List <SnapshotDataStoreVO > snapshots = snapshotDataStoreDao .listByStoreId (srcDataStoreId , DataStoreRole .Image );
116119 List <VolumeDataStoreVO > volumes = volumeDataStoreDao .listByStoreId (srcDataStoreId );
117- return filesReadyToMigrate (srcDataStoreId , templates , snapshots , volumes );
120+
121+ return filesReadyToMigrate (templates , snapshots , volumes );
118122 }
119123
120124 protected void checkIfCompleteMigrationPossible (ImageStoreService .MigrationPolicy policy , Long srcDataStoreId ) {
@@ -163,29 +167,40 @@ public int compare(Map.Entry<Long, Pair<Long, Long>> e1, Map.Entry<Long, Pair<Lo
163167 }
164168
165169 protected List <DataObject > getSortedValidSourcesList (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ,
166- 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 ) {
167171 List <DataObject > files = new ArrayList <>();
168172
169173 files .addAll (getAllReadyTemplates (srcDataStore , childTemplates , templates ));
170- files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots ));
174+ files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots , snapshotIdsToMigrate ));
171175
172176 files = sortFilesOnSize (files , snapshotChains );
173177
174178 return files ;
175179 }
176180
177181 protected List <DataObject > getSortedValidSourcesList (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ,
178- Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates ) {
182+ Map <DataObject , Pair <List <TemplateInfo >, Long >> childTemplates , Set < Long > snapshotIdsToMigrate ) {
179183 List <DataObject > files = new ArrayList <>();
180184 files .addAll (getAllReadyTemplates (srcDataStore , childTemplates ));
181- files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains ));
185+ files .addAll (getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshotIdsToMigrate ));
182186 files .addAll (getAllReadyVolumes (srcDataStore ));
183187
184188 files = sortFilesOnSize (files , snapshotChains );
185189
186190 return files ;
187191 }
188192
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+
189204 protected List <DataObject > sortFilesOnSize (List <DataObject > files , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ) {
190205 Collections .sort (files , new Comparator <DataObject >() {
191206 @ Override
@@ -261,16 +276,24 @@ protected boolean shouldMigrateTemplate(TemplateDataStoreVO template, VMTemplate
261276 * for each parent snapshot and the cumulative size of the chain - this is done to ensure that all the snapshots in a chain
262277 * are migrated to the same datastore
263278 */
264- protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , List <SnapshotDataStoreVO > snapshots ) {
279+ protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , List <SnapshotDataStoreVO > snapshots , Set < Long > snapshotIdsToMigrate ) {
265280 List <SnapshotInfo > files = new LinkedList <>();
281+ Set <Long > snapshotIdsAlreadyInChain = new HashSet <>();
266282 for (SnapshotDataStoreVO snapshot : snapshots ) {
267283 SnapshotVO snapshotVO = snapshotDao .findById (snapshot .getSnapshotId ());
268284 if (snapshot .getState () == ObjectInDataStoreStateMachine .State .Ready &&
269- snapshotVO != null && snapshotVO .getHypervisorType () != Hypervisor .HypervisorType .Simulator
270- && snapshot .getParentSnapshotId () == 0 ) {
271- SnapshotInfo snap = snapshotFactory .getSnapshot (snapshotVO .getSnapshotId (), snapshot .getDataStoreId (), snapshot .getRole ());
272- if (snap != null ) {
273- files .add (snap );
285+ snapshotVO != null && snapshotVO .getHypervisorType () != Hypervisor .HypervisorType .Simulator ) {
286+ if (snapshotVO .getHypervisorType () == Hypervisor .HypervisorType .KVM && snapshot .getKvmCheckpointPath () != null && !snapshotIdsAlreadyInChain .contains (snapshotVO .getId ())) {
287+ List <SnapshotInfo > kvmIncrementalSnapshotChain = createKvmIncrementalSnapshotChain (snapshot );
288+ SnapshotInfo parent = kvmIncrementalSnapshotChain .get (0 );
289+ snapshotIdsAlreadyInChain .addAll (kvmIncrementalSnapshotChain .stream ().map (DataObject ::getId ).collect (Collectors .toSet ()));
290+ snapshotChains .put (parent , new Pair <>(kvmIncrementalSnapshotChain , getTotalChainSize (kvmIncrementalSnapshotChain .stream ().filter (snap -> snapshotIdsToMigrate .contains (snap .getId ())).collect (Collectors .toList ()))));
291+ files .add (parent );
292+ } else if (snapshot .getParentSnapshotId () == 0 ) {
293+ SnapshotInfo snap = snapshotFactory .getSnapshot (snapshotVO .getSnapshotId (), snapshot .getDataStoreId (), snapshot .getRole ());
294+ if (snap != null ) {
295+ files .add (snap );
296+ }
274297 }
275298 }
276299 }
@@ -285,15 +308,16 @@ protected List<DataObject> getAllReadySnapshotsAndChains(DataStore srcDataStore,
285308 chain .addAll (children );
286309 }
287310 }
288- snapshotChains .put (parent , new Pair <List < SnapshotInfo >, Long >(chain , getTotalChainSize (chain )));
311+ snapshotChains .putIfAbsent (parent , new Pair <>(chain , getTotalChainSize (chain )));
289312 }
290313
291314 return (List <DataObject >) (List <?>) files ;
292315 }
293316
294- protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains ) {
317+ protected List <DataObject > getAllReadySnapshotsAndChains (DataStore srcDataStore , Map <DataObject , Pair <List <SnapshotInfo >, Long >> snapshotChains , Set < Long > snapshotIdsToMigrate ) {
295318 List <SnapshotDataStoreVO > snapshots = snapshotDataStoreDao .listByStoreId (srcDataStore .getId (), DataStoreRole .Image );
296- return getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots );
319+ snapshotIdsToMigrate .addAll (snapshots .stream ().map (SnapshotDataStoreVO ::getSnapshotId ).collect (Collectors .toSet ()));
320+ return getAllReadySnapshotsAndChains (srcDataStore , snapshotChains , snapshots , snapshotIdsToMigrate );
297321 }
298322
299323 protected Long getTotalChainSize (List <? extends DataObject > chain ) {
0 commit comments