package org.openstack.atlas.usagerefactor.collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openstack.atlas.service.domain.entities.Host;
import org.openstack.atlas.service.domain.entities.LoadBalancer;
import org.openstack.atlas.service.domain.exceptions.UsageEventCollectionException;
import org.openstack.atlas.usagerefactor.SnmpStats;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@Component
public class StatsCollection {
private final Log LOG = LogFactory.getLog(StatsCollection.class);
private ThreadPoolExecutor poolExecutor;
public StatsCollection() {
}
public List<SnmpStats> getStatsForHosts(LoadBalancer lb, List<Host> hosts) throws UsageEventCollectionException {
if (hosts != null && !hosts.isEmpty()) {
LOG.debug("Collecting SNMP stats for load balancer: " + lb.getId());
List<Future<SnmpStats>> futures;
List<Callable<SnmpStats>> callables = new ArrayList<Callable<SnmpStats>>();
for (Host h : hosts) {
callables.add(new SnmpStatsCollector(h, lb));
}
ExecutorService threadPool = Executors.newFixedThreadPool(hosts.size());
try {
LOG.debug("Executing SNMP stats collection tasks for load balancer: " + lb.getId());
futures = threadPool.invokeAll(callables);
} catch (InterruptedException e) {
LOG.error("Error executing SNMP stats collection: " + e);
throw new UsageEventCollectionException("Error executing SNMP stats collection: ", e);
} finally {
shutdownAndAwaitTermination(threadPool);
}
List<SnmpStats> snmpStats = new ArrayList<SnmpStats>();
for (Future<SnmpStats> f : futures) {
try {
SnmpStats stats = f.get();
if (stats != null) {
snmpStats.add(stats);
} else {
LOG.warn("A null SnmpStats was encountered by will not be used for processing.");
}
} catch (InterruptedException e) {
LOG.error("Error retrieving SNMP futures: " + e);
throw new UsageEventCollectionException("Error retrieving SNMP futures: ", e);
} catch (ExecutionException e) {
LOG.error("Error retrieving SNMP futures: " + e);
throw new UsageEventCollectionException("Error retrieving SNMP futures: ", e);
}
}
return snmpStats;
} else {
LOG.error("Hosts data invalid, this shouldn't happen... Verify DB for data and notify developer immediately. ");
throw new UsageEventCollectionException("Hosts data invalid, please contact support.");
}
}
private void shutdownAndAwaitTermination(ExecutorService pool) {
final int THREAD_POOL_TIMEOUT = 30;
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(THREAD_POOL_TIMEOUT, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(THREAD_POOL_TIMEOUT, TimeUnit.SECONDS))
LOG.error(String.format("Pool '%s' did not terminate!", pool.toString()));
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}