/*******************************************************************************
* 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.List;
import org.apache.log4j.Logger;
import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
import org.gluster.storage.management.core.model.ServerStats;
import org.gluster.storage.management.core.model.ServerStatsRow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
*/
@Component
public abstract class AbstractStatsFactory implements StatsFactory {
@Autowired
protected ServerUtil serverUtil;
private Logger logger = Logger.getLogger(AbstractStatsFactory.class);
protected ServerStats getFirstOnlineServerStats(List<String> serverNames, String period,
boolean removeServerOnError, boolean removeOnlineServer) {
for(int i = serverNames.size() - 1; i >= 0; i--) {
String serverName = serverNames.get(i);
try {
ServerStats stats = fetchStats(serverName, period);
if(removeOnlineServer) {
serverNames.remove(serverName);
}
return stats;
} 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;
}
int rowCount = aggregatedStats.getMetadata().getRowCount();
int columnCount = aggregatedStats.getMetadata().getLegend().size();
int[][] dataCount = initDataCountArray(rowCount, columnCount);
List<ServerStats> allStats = serverUtil.executeScriptOnServers(serverNames, getStatsScriptName() + " " + period, ServerStats.class, false);
for (ServerStats stats : allStats) {
// add to aggregated stats
addServerStats(stats, aggregatedStats, dataCount);
}
averageAggregatedStats(aggregatedStats, dataCount);
}
/**
*
* @param statsToBeAdded
* @param targetStats
* @param dataCount Each element of this matrix will be incremented for every valid element added
* @return
*/
protected List<ServerStatsRow> addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) {
List<ServerStatsRow> serverStatsRows = statsToBeAdded.getRows();
for (int rowNum = 0; rowNum < serverStatsRows.size() && rowNum < targetStats.getMetadata().getRowCount()
&& rowNum < dataCount.length; rowNum++) {
ServerStatsRow row = serverStatsRows.get(rowNum);
List<Double> rowData = row.getUsageData();
List<Double> aggregatedStatsRowData = targetStats.getRows().get(rowNum).getUsageData();
for(int i = 1; i < targetStats.getMetadata().getLegend().size(); i++) {
// Add the data
Double data = rowData.get(i);
if(!data.isNaN()) {
// data is available. add it.
Double oldData = aggregatedStatsRowData.get(i);
if(oldData.isNaN()) {
oldData = 0d;
}
aggregatedStatsRowData.set(i, oldData + data);
// increment record count. this will be used for calculating average of aggregated data.
dataCount[rowNum][i]++;
}
}
}
return serverStatsRows;
}
protected void averageAggregatedStats(ServerStats aggregatedStats, int[][] dataCount) {
List<ServerStatsRow> rows = aggregatedStats.getRows();
for(int rowNum = 0; rowNum < rows.size() && rowNum < dataCount.length; rowNum++) {
List<Double> data = rows.get(rowNum).getUsageData();
for(int columnNum = 0; columnNum < data.size(); columnNum++) {
data.set(columnNum, data.get(columnNum) / dataCount[rowNum][columnNum]);
}
}
}
protected int[][] initDataCountArray(int rowCount, int columnCount) {
int[][] dataCount = new int[rowCount][columnCount];
// initialize all data counts to 1
for(int rowNum = 0; rowNum < rowCount; rowNum++) {
for(int columnNum = 0; columnNum < columnCount; columnNum++) {
dataCount[rowNum][columnNum] = 1;
}
}
return dataCount;
}
@Override
public ServerStats fetchAggregatedStats(List<String> serverNames, String period) {
if(serverNames == null || serverNames.size() == 0) {
throw new GlusterRuntimeException("No server names passed to fetchAggregaredStats!");
}
ServerStats firstServerStats = getFirstOnlineServerStats(serverNames, period, true, true);
ServerStats aggregatedStats = new ServerStats(firstServerStats);
aggregateStats(serverNames, aggregatedStats, period);
return aggregatedStats;
}
@Override
public ServerStats fetchStats(String serverName, String period, String...args) {
String argsStr = "";
for (String arg : args) {
if(arg != null) {
argsStr += " " + arg;
}
}
return serverUtil.executeScriptOnServer(serverName, getStatsScriptName() + argsStr + " " + period,
ServerStats.class);
}
public abstract String getStatsScriptName();
}