summaryrefslogtreecommitdiffstats
path: root/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java
blob: fdc4b1d28afc8f8b9b06415f0e3dcc0a6a961bf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*******************************************************************************
 * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
 * This file is part of Gluster Management Console.
 *
 * Gluster Management Console is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU Affero 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 Console 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 Affero General Public License
 * for more details.
 *  
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package com.gluster.storage.management.gateway.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
import com.gluster.storage.management.core.model.NetworkInterface;
import com.gluster.storage.management.core.model.Server;
import com.gluster.storage.management.core.model.ServerStats;
import com.gluster.storage.management.core.model.ServerStatsRow;
import com.gluster.storage.management.core.utils.ProcessUtil;

/**
 *
 */
@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;
	}
}