/*******************************************************************************
* Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com>
* This file is part of Gluster Management Gateway.
*
* Gluster Management Gateway is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* Gluster Management Gateway is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*******************************************************************************/
package org.gluster.storage.management.gateway.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
import org.gluster.storage.management.core.model.NetworkInterface;
import org.gluster.storage.management.core.model.Server;
import org.gluster.storage.management.core.model.ServerStats;
import org.gluster.storage.management.core.model.ServerStatsRow;
import org.gluster.storage.management.core.utils.ProcessUtil;
import org.springframework.stereotype.Component;
/**
*
*/
@Component
public class NetworkStatsFactory extends AbstractStatsFactory {
private static final Logger logger = Logger.getLogger(NetworkStatsFactory.class);
private static final String NETWORK_STATS_SCRIPT = "get_rrd_net_details.py";
private int[][] dataCount;
@Override
public String getStatsScriptName() {
return NETWORK_STATS_SCRIPT;
}
@Override
protected ServerStats getFirstOnlineServerStats(List<String> serverNames, String period,
boolean removeServerOnError, boolean removeOnlineServer) {
ServerStats firstOnlineServerStats = null;
for(int i = serverNames.size() - 1; i >= 0; i--) {
String serverName = serverNames.get(i);
Server server = new Server(serverName);
serverUtil.fetchServerDetails(server);
if(!server.isOnline()) {
if(removeServerOnError) {
// server is offline. no point in trying to fetch it's details.
serverNames.remove(serverName);
}
continue;
}
try {
for(NetworkInterface networkInterface : server.getNetworkInterfaces()) {
ServerStats stats = fetchStats(serverName, period, networkInterface.getName());
if(firstOnlineServerStats == null) {
firstOnlineServerStats = stats;
int rowCount = firstOnlineServerStats.getMetadata().getRowCount();
int columnCount = firstOnlineServerStats.getMetadata().getLegend().size();
dataCount = initDataCountArray(rowCount, columnCount);
} else {
addServerStats(stats, firstOnlineServerStats, dataCount);
}
}
if(removeOnlineServer) {
serverNames.remove(serverName);
}
return firstOnlineServerStats;
} catch(Exception e) {
// server might be offline - continue with next one
logger.warn("Couldn't fetch stats from server [" + serverName + "]!", e);
if(removeServerOnError) {
serverNames.remove(serverName);
}
continue;
}
}
throw new GlusterRuntimeException("All servers offline!");
}
protected void aggregateStats(List<String> serverNames, ServerStats aggregatedStats, String period) {
if(serverNames.isEmpty()) {
return;
}
List<ServerStats> statsList = Collections.synchronizedList(new ArrayList<ServerStats>());
try {
List<Thread> threads = createThreads(serverNames, period, statsList);
ProcessUtil.waitForThreads(threads);
for(ServerStats stats : statsList) {
addServerStats(stats, aggregatedStats, dataCount);
}
} catch (InterruptedException e) {
String errMsg = "Exception while aggregating network statistics on servers [" + serverNames
+ "] for period [" + period + "]! Error: [" + e.getMessage() + "]";
logger.error(errMsg, e);
throw new GlusterRuntimeException(errMsg, e);
}
averageAggregatedStats(aggregatedStats, dataCount);
}
private <T> List<Thread> createThreads(List<String> serverNames, String period, List<ServerStats> statsList)
throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>();
for (int i = serverNames.size()-1; i >= 0 ; i--) {
Thread thread = new NetworkStatsThread(serverNames.get(i), period, statsList);
threads.add(thread);
thread.start();
if(i >= 5 && i % 5 == 0) {
// After every 5 servers, wait for 1 second so that we don't end up with too many running threads
Thread.sleep(1000);
}
}
return threads;
}
public class NetworkStatsThread extends Thread {
private String serverName;
private String period;
private List<ServerStats> statsList;
public NetworkStatsThread(String serverName, String period, List<ServerStats> statsList) {
this.serverName = serverName;
this.period = period;
this.statsList = statsList;
}
@Override
public void run() {
try {
Server server = new Server(serverName);
serverUtil.fetchServerDetails(server);
for (NetworkInterface networkInterface : server.getNetworkInterfaces()) {
// fetch the stats and add to aggregated stats
statsList.add(fetchStats(serverName, period, networkInterface.getName()));
}
} catch(Exception e) {
// server might be offline - continue with next one
logger.warn("Couldn't fetch Network stats from server [" + serverName + "]!", e);
}
}
}
@Override
public ServerStats fetchStats(String serverName, String period, String... args) {
ServerStats stats = super.fetchStats(serverName, period, args);
// the data returned by rrd contains "bytes/sec". Update the stats object to represent KiB/s
for(ServerStatsRow row : stats.getRows()) {
List<Double> data = row.getUsageData();
for (int i = 0; i < data.size(); i++) {
Double val = data.get(i);
data.set(i, val / 1024);
}
}
return stats;
}
}