/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.placement;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.DiscoveredDataObject.Type;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.VirtualArray;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.volumecontroller.Recommendation;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
/**
* StorageScheduler service for Object storage. StorageScheduler is done based on desired
* class-of-service parameters for the provisioned storage.
*/
public class BucketScheduler {
public final Logger _log = LoggerFactory.getLogger(BucketScheduler.class);
private DbClient _dbClient;
private StorageScheduler _scheduler;
public void setDbClient(DbClient dbClient) {
_dbClient = dbClient;
}
public void setScheduleUtils(StorageScheduler scheduleUtils) {
_scheduler = scheduleUtils;
}
/**
* Schedule storage for Object in the varray with the given CoS capabilities.
*
* @param vArray
* @param vPool
* @param capabilities
* @param attributeMap
* @return
*/
public List<BucketRecommendation> placeBucket(VirtualArray vArray, VirtualPool vPool,
VirtualPoolCapabilityValuesWrapper capabilities, Map<String, Object> attributeMap) {
_log.debug("Schedule storage for {} resource(s) of size {}.", capabilities.getResourceCount(), capabilities.getSize());
// Get all storage pools that match the passed vpool params and
// protocols. In addition, the pool must have enough capacity
// to hold at least one resource of the requested size.
List<StoragePool> candidatePools = _scheduler.getMatchingPools(vArray, vPool, capabilities, attributeMap);
// Get the recommendations for the candidate pools.
List<Recommendation> poolRecommendations =
_scheduler.getRecommendationsForPools(vArray.getId().toString(), candidatePools, capabilities);
List<BucketRecommendation> recommendations =
selectMatchingStoragePool(vPool, poolRecommendations);
// We need to place all the resources. If we can't then
// log an error and clear the list of recommendations.
if (recommendations.isEmpty()) {
_log.error(
"Could not find matching pools for virtual array {} & vpool {}",
vArray.getId(), vPool.getId());
}
return recommendations;
}
/**
* Select the right matching storage pools
*
* @param vpool
* @param poolRecommends recommendations after selecting matching storage pools.
* @return list of Bucket Recommendation
*/
private List<BucketRecommendation> selectMatchingStoragePool(VirtualPool vpool, List<Recommendation> poolRecommends) {
List<BucketRecommendation> baseResult = new ArrayList<BucketRecommendation>();
for (Recommendation recommendation : poolRecommends) {
BucketRecommendation rec = new BucketRecommendation(recommendation);
URI storageUri = recommendation.getSourceStorageSystem();
// Verify if the Storage System is an Object Store
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageUri);
if (!Type.isObjectStorageSystem(StorageSystem.Type.valueOf(storage.getSystemType()))) {
continue;
}
baseResult.add(rec);
}
List<BucketRecommendation> finalResult = null;
//Make sure pool list is not empty
if (!baseResult.isEmpty()) {
finalResult = new ArrayList<BucketRecommendation>();
//sort the storage pools based on the number of datacenters spread
storagePoolSort(baseResult);
//get the value of datacenters in the sorted first storage pool
StoragePool pool = _dbClient.queryObject(StoragePool.class, baseResult.get(0).getSourceStoragePool());
Integer baseDC = pool.getDataCenters();
//make the first sub-set of pools
for (BucketRecommendation bkRec:baseResult) {
URI storagePoolUri = bkRec.getSourceStoragePool();
pool = _dbClient.queryObject(StoragePool.class, storagePoolUri);
if (pool.getDataCenters() == baseDC) {
finalResult.add(bkRec);
}
else {
break;
}
}
} else {
finalResult = baseResult;
}
return finalResult;
}
private void storagePoolSort(List<BucketRecommendation> baseResult) {
Collections.sort(baseResult, new Comparator<BucketRecommendation>() {
@Override
public int compare(BucketRecommendation bucketRec1, BucketRecommendation bucketRec2) {
URI storagePoolUri1 = bucketRec1.getSourceStoragePool();
StoragePool pool1 = _dbClient.queryObject(StoragePool.class, storagePoolUri1);
URI storagePoolUri2 = bucketRec2.getSourceStoragePool();
StoragePool pool2 = _dbClient.queryObject(StoragePool.class, storagePoolUri2);
//pool1 DC > pool2 DC -> +ve
//pool1 DC == pool2 DC -> 0
//pool1 DC < pool2 DC -> -ve
return (pool1.getDataCenters() - pool2.getDataCenters());
}
});//end sort method
}
}