/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.Volume; import com.google.common.base.Joiner; /** * This callback function will be invoked from within in the SmisCommandHelper * .callRefreshSystem method. Reason: we need to run this after the refresh is complete * to update any *other* snapshots or volumes are known to also require a refresh. The * EMCRefresh call updates the SMI-S provider's database. Presumably, * all changes on the array will be all sync'ed after the call, * so we will need to reflect that against any other snapshots/volumes that required it, * but may not have yet invoked an operation that required the refresh. Essentially, * we preemptively updating these because we know they should be in-sync now. */ public class RefreshRequiredUpdateFunction implements SimpleFunction { private static final Logger _log = LoggerFactory.getLogger(RefreshRequiredUpdateFunction.class); public static final String REFRESH_REQUIRED = "refreshRequired"; public static final String STORAGE_DEVICE = "storageDevice"; private URI storageURI; private List<URI> objsRequiringRefresh; private DbClient dbClient; public RefreshRequiredUpdateFunction(URI storageURI, List<URI> originalList, DbClient dbClient) { this.storageURI = storageURI; this.objsRequiringRefresh = originalList; this.dbClient = dbClient; } @Override public void call() { _log.info(String.format("Original list of uris requiring EMCRefresh:%n%s", Joiner.on(',').join(objsRequiringRefresh))); handleBlockObjects(Volume.class); handleBlockObjects(BlockSnapshot.class); } /** * Refresh block objects of given type * * @param clazz CF subclass of BlockObject */ private <T extends BlockObject> void handleBlockObjects(Class<T> clazz) { // get all object URIs contained by the StorageSystem URIQueryResultList queryResults = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory.getContainedObjectsConstraint(storageURI, clazz, STORAGE_DEVICE), queryResults); Iterator<URI> iQueryResults = queryResults.iterator(); List<URI> blockObjectURIs = new ArrayList<URI>(); while (iQueryResults.hasNext()) { blockObjectURIs.add(iQueryResults.next()); } // merge with objsRequiringRefresh for (URI uri : objsRequiringRefresh) { if (URIUtil.isType(uri, clazz)) { // uri could have already been in blockObjectURIs // queryIterativeObjectField won't return duplicate objects even if there are duplicate URIs in the list blockObjectURIs.add(uri); } } // query all objects, only need the REFRESH_REQUIRED field Iterator<T> iBlockObjects = dbClient.queryIterativeObjectField(clazz, REFRESH_REQUIRED, blockObjectURIs); List<T> objsNeedRefresh = new ArrayList<T>(); // loop all the objects, check if the refreshRequired is true. while (iBlockObjects.hasNext()) { T blockObject = iBlockObjects.next(); if (blockObject.getRefreshRequired()) { blockObject.setRefreshRequired(false); objsNeedRefresh.add(blockObject); } } dbClient.persistObject(objsNeedRefresh); } }