/*
* (C) Copyright IBM Corp. 2009
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.apps.dashboard;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.ibm.gaiandb.apps.MetricMonitor;
import java.awt.Color;
public abstract class MetricValueProcessor {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2009";
private static final Color[] STANDARD_COLOR_PALETTE = new Color[] {
// new Color(0x00FF00), // green
// new Color(0x66CCFF), // sky blue
// new Color(0x800080), // purple
// new Color(0xDDA0DD), // plum
// new Color(0xFFC8CB) // pink
new Color(0x0000FF), // blue
new Color(0xFFFF00), // yellow
new Color(0xFF0000) // red
};
private static final Color[] REVERSED_COLOR_PALETTE = new Color[] {
new Color(0xFF0000),
new Color(0xFFFF00),
// new Color(0x66CCFF), // sky blue
new Color(0x0000FF), // blue
// new Color(0x00FF00)
};
private static final Color[] TEMPERATURE_COLOR_PALETTE = new Color[] {
new Color(0x66CCFF),
new Color(0x00FF00),
new Color(0xFFFF00),
new Color(0xFF6600),
new Color(0xFF0000)
};
// private static final Color[] TEMPERATURE_COLOR_PALETTE = new Color[] {
// new Color(0xFF0000),
// new Color(0xFF6600),
// new Color(0xFFFF00),
// new Color(0x00FF00),
// new Color(0x66CCFF)
// };
private static final String METRIC_ECCENTRICITY = "Eccentricity";
private static final String METRIC_CONNECTIVITY = "Connectivity";
private static final String METRIC_THROUGHPUT = "Data Throughput";
private static final String METRIC_QRY_ACTIVITY = "Query Activity";
private static final String METRIC_NODE_CPU = "Node CPU";
// private static final String METRIC_DS_CPU = "DS CPU";
private static final String METRIC_MEM_JVM = "JVM Used Memory";
private static final String METRIC_CPU = "CPU";
private static final String METRIC_MEM = "Used Memory";
private static final String METRIC_DISK_IO = "Disk I/O";
private static final String METRIC_NET_IO = "Network I/O";
private static final String METRIC_BATTERY = "Battery Charge";
private static final String METRIC_TEMPERATURE = "Temperature";
// private static final Set<String> sensorMetricNames = new HashSet<String>( Arrays.asList(
// new String[] { METRIC_CPU, METRIC_MEM, METRIC_DISK_IO, METRIC_NET_IO, METRIC_BATTERY, METRIC_TEMPERATURE } ) );
// private static final Set<String> gaianMetricNames = new HashSet<String>( Arrays.asList(
// new String[] { METRIC_THROUGHPUT, METRIC_MEM_JVM } ) );
static final String[] internalMetrics = new String[] { METRIC_ECCENTRICITY, METRIC_CONNECTIVITY };
static final Set<String> internalMetricsSet = new HashSet<String>( Arrays.asList( internalMetrics ) );
public static final MonitorInfo[] MONITORS = {
// Absolute measure. Note also in future: should max connections be a hard bound ?
new MonitorInfo(METRIC_CONNECTIVITY, "CONN", "Links", new String[0],
false, 0, 10, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_CONNECTIVITY)),
// Relative measure.
new MonitorInfo(METRIC_ECCENTRICITY, "ECCE", "Steps", new String[0],
false, 0, 5, REVERSED_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_ECCENTRICITY)),
// Relative.
new MonitorInfo(METRIC_THROUGHPUT, "THRU", "KB/s", new String[] { METRIC_THROUGHPUT },
false, 0, 100, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_THROUGHPUT)),
// Relative.
new MonitorInfo(METRIC_QRY_ACTIVITY, "ACTIV", "ms/s", new String[] { METRIC_QRY_ACTIVITY },
false, 0, 2000, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_QRY_ACTIVITY)),
// Absolute.
new MonitorInfo(METRIC_NODE_CPU, "NCPU", "%", new String[] { METRIC_NODE_CPU },
false, 0, 20, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_NODE_CPU)),
// // Absolute.
// new MonitorInfo(METRIC_DS_CPU, "DSCPU", "%", new String[] { METRIC_DS_CPU },
// false, 0, 10, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_DS_CPU)),
// Absolute.
new MonitorInfo(METRIC_MEM_JVM, "JMEM", "%", new String[] { METRIC_MEM_JVM },
true, 0, 100, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever(METRIC_MEM_JVM)),
new MonitorInfo(METRIC_CPU, "CPU", "%", new String[] { "CPU Usage" },
true, 0, 100, STANDARD_COLOR_PALETTE, new MonitorInfo.DefaultValueRetriever("CPU Usage")),
new MonitorInfo(METRIC_MEM, "MEM", "%", new String[] { "Used Memory", "Total Memory" },
true, 0, 100, STANDARD_COLOR_PALETTE,
new MonitorInfo.ValueRetriever() {
public Integer get(Map<String, Integer> currentValues) {
Integer usedMemory = currentValues.get("Used Memory");
Integer totalMemory = currentValues.get("Total Memory");
if (null != usedMemory && null != totalMemory) {
return usedMemory * 100 / totalMemory;
}
else {
return null;
}
}
}),
new MonitorInfo(METRIC_DISK_IO, "DISK", "KB/s", new String[] { "Disk I/O" },
false, 0, 10000, STANDARD_COLOR_PALETTE,
new MonitorInfo.DefaultValueRetriever(METRIC_DISK_IO)),
new MonitorInfo(METRIC_NET_IO, "NET", "KB/s", new String[] { "Network I/O" },
false, 0, 500, STANDARD_COLOR_PALETTE,
new MonitorInfo.DefaultValueRetriever(METRIC_NET_IO)),
new MonitorInfo(METRIC_BATTERY, "BAT", "%", new String[] { "Battery Power" },
true, 0, 100, REVERSED_COLOR_PALETTE,
new MonitorInfo.DefaultValueRetriever("Battery Power")),
new MonitorInfo(METRIC_TEMPERATURE, "TEMP", MetricMonitor.TEMPERATURE_SYMBOL + "C", new String[] { "Temperature" },
true, 0, 100, TEMPERATURE_COLOR_PALETTE,
new MonitorInfo.DefaultValueRetriever(METRIC_TEMPERATURE))
};
// private static final String SQL_HISTORICAL_METRICS =
// " SELECT gdb_node," +
// " jSecs(CURRENT_TIMESTAMP) - age received_timestamp," +
// " name," +
// " CAST(value AS INT) value" +
// " FROM new com.ibm.db2j.GaianQuery(" +
// " 'SELECT name, jSecs(CURRENT_TIMESTAMP) - jSecs(received_timestamp) age, value FROM gdb_local_metrics " +
// " UNION SELECT ''Throughput'' name, 0 age, cast(GDB_THROUGHPUT() as char(20)) value from sysibm.sysdummy1 " +
// " UNION SELECT ''JVM Used Memory'' name, 0 age, cast(JMEMORYPERCENT() as char(3)) value from sysibm.sysdummy1', " +
// " 'with_provenance') Q" +
// " WHERE name IN ($monitors)" +
// " AND age < ?" +
// " ORDER BY gdb_node, received_timestamp, name";
private static final String SQL_HISTORICAL_METRICS =
" SELECT gdb_node," +
" jSecs(CURRENT_TIMESTAMP) - age received_timestamp," +
" name," +
" CAST(value AS INT) value" +
" FROM new com.ibm.db2j.GaianQuery(" +
" 'SELECT name, jSecs(CURRENT_TIMESTAMP) - jSecs(received_timestamp) age, value FROM gdb_local_metrics " +
" UNION SELECT ''Data Throughput'' name, 0 age, cast(GDB_THROUGHPUT()/1000 as char(20)) value from sysibm.sysdummy1 " +
" UNION SELECT ''Query Activity'' name, 0 age, cast(GDB_QRY_ACTIVITY() as char(20)) value from sysibm.sysdummy1 " +
" UNION SELECT ''Node CPU'' name, 0 age, cast(GDB_NODE_CPU() as char(3)) value from sysibm.sysdummy1 " +
// " UNION SELECT ''DS CPU'' name, 0 age, cast(GDB_DS_CPU() as char(3)) value from sysibm.sysdummy1 " +
" UNION SELECT ''JVM Used Memory'' name, 0 age, cast(JMEMORYPERCENT() as char(3)) value from sysibm.sysdummy1', " +
" 'with_provenance') Q" +
" WHERE name IN ($monitors)" +
" AND age < ?" +
" ORDER BY gdb_node, received_timestamp, name";
private static final String SQL_LATEST_METRICS =
" SELECT gdb_node," +
" max( jSecs(CURRENT_TIMESTAMP) - age ) received_timestamp," +
" name," +
" max( CAST(value AS INT) ) value" +
" FROM new com.ibm.db2j.GaianQuery(" +
" 'SELECT name, jSecs(CURRENT_TIMESTAMP) - jSecs(received_timestamp) age, value FROM gdb_local_metrics " +
" UNION SELECT ''Data Throughput'' name, 0 age, cast(GDB_THROUGHPUT()/1000 as char(20)) value from sysibm.sysdummy1 " +
" UNION SELECT ''Query Activity'' name, 0 age, cast(GDB_QRY_ACTIVITY() as char(20)) value from sysibm.sysdummy1 " +
" UNION SELECT ''Node CPU'' name, 0 age, cast(GDB_NODE_CPU() as char(3)) value from sysibm.sysdummy1 " +
// " UNION SELECT ''DS CPU'' name, 0 age, cast(GDB_DS_CPU() as char(3)) value from sysibm.sysdummy1 " +
" UNION SELECT ''JVM Used Memory'' name, 0 age, cast(JMEMORYPERCENT() as char(3)) value from sysibm.sysdummy1', " +
" 'with_provenance') Q" +
" WHERE name IN ($monitors)" +
" AND age < ?" +
" GROUP BY gdb_node, name";
private MonitorInfo[] monitors;
private Connection conn;
private PreparedStatement statement, statementLatestMetrics;
public MetricValueProcessor(Connection conn) throws SQLException {
this.conn = conn;
}
public void setAllMonitors() throws SQLException {
setMonitors(MONITORS);
}
public MonitorInfo[] getMonitors() {
return monitors;
}
private boolean hasExternalMetricMonitor() {
for ( MonitorInfo mi : monitors )
if ( !internalMetricsSet.contains(mi.name) ) return true;
return false;
}
// private boolean hasSensorMetricMonitor() {
// for ( MonitorInfo mi : monitors )
// if ( sensorMetricNames.contains(mi.name) ) return true;
// return false;
// }
// private boolean hasGaianMetricMonitor() {
// for ( MonitorInfo mi : monitors )
// if ( !gaianMetricNames.contains(mi.name) ) return true;
// return false;
// }
public void setMonitors(MonitorInfo[] monitors) throws SQLException {
this.monitors = monitors;
if (null != this.monitors && hasExternalMetricMonitor()) {
statement = conn.prepareStatement(
SQL_HISTORICAL_METRICS.replace("$monitors", MonitorInfo.getRequiredMetricsAsSql(this.monitors)));
statementLatestMetrics = conn.prepareStatement(
SQL_LATEST_METRICS.replace("$monitors", MonitorInfo.getRequiredMetricsAsSql(this.monitors)));
statement.setQueryTimeout(Dashboard.QUERY_TIMEOUT); // probably (?) has no effect
}
else {
statement = null;
statementLatestMetrics = null;
}
}
public void clearMonitors() {
monitors = null;
statement = null;
statementLatestMetrics = null;
}
public void processLatestMetrics(int maxAge) throws SQLException {
ResultSet rs = null;
if ( null != statementLatestMetrics ) {
statementLatestMetrics.setInt(1, maxAge);
rs = statementLatestMetrics.executeQuery();
}
process(rs, false);
}
public void processHistoricalMetrics(int maxAge) throws SQLException {
ResultSet rs = null;
if ( null != statement ) {
statement.setInt(1, maxAge);
rs = statement.executeQuery();
}
process(rs, true);
}
private void process(ResultSet rs, boolean processByTimestamp) throws SQLException {
if (null != monitors) {
int currentTimestamp = (int) System.currentTimeMillis();
// internal metrics
if ( null != topologyGraph ) {
for ( String node : topologyGraph.getAllNodes() ) {
Map<MonitorInfo, Integer> timestampValues = new HashMap<MonitorInfo, Integer>(monitors.length);
for (MonitorInfo monitor : monitors) {
if ( monitor.name.equals(METRIC_ECCENTRICITY) ) {
timestampValues.put(monitor, topologyGraph.getEccentricity(node));
// apply relative min and max colour bounds
monitor.minBound = Math.max( 0, topologyGraph.getRadius()-2 );
monitor.maxBound = topologyGraph.getDiameter() + 2;
} else if ( monitor.name.equals(METRIC_CONNECTIVITY) )
timestampValues.put(monitor, topologyGraph.getConnectivity(node));
}
add(node, currentTimestamp, timestampValues);
}
}
if ( null != rs ) {
// Construct HashMap of monitor values for each node at each distinct timestamp
String currentNode = null;
Map<String, Integer> currentValues = null;
currentTimestamp = 0;
updateBounds();
while (rs.next()) {
String node = rs.getString("GDB_NODE");
String monitorType = rs.getString("NAME");
int timestamp = processByTimestamp ? rs.getInt("RECEIVED_TIMESTAMP") : 0;
int value = rs.getInt("VALUE");
if (!node.equals(currentNode) || timestamp != currentTimestamp) {
processTimestamp(currentNode, currentTimestamp, currentValues);
currentNode = node;
currentTimestamp = timestamp;
currentValues = new HashMap<String, Integer>();
}
currentValues.put(monitorType, value);
}
processTimestamp(currentNode, currentTimestamp, currentValues);
}
}
}
private Map<MonitorInfo, Integer> maxBounds = new HashMap<MonitorInfo, Integer>();
private void updateBounds() {
for (MonitorInfo monitor : monitors) {
Integer max = maxBounds.get(monitor);
if ( null != max ) monitor.maxBound = max;
}
maxBounds.clear();
}
private void checkBounds( MonitorInfo monitor, Integer value ) {
if ( null == value ) return;
Integer v = maxBounds.get(monitor);
if ( null == v ) maxBounds.put(monitor, Math.max(monitor.defaultMaxBound, value));
else if ( value > v ) maxBounds.put(monitor, value);
}
private void processTimestamp(String node, int timestamp, Map<String, Integer> values) {
if (null != values) {
Map<MonitorInfo, Integer> timestampValues = new HashMap<MonitorInfo, Integer>(monitors.length);
for (MonitorInfo monitor : monitors) {
Integer value = monitor.valueRetriever.get(values);
checkBounds( monitor, value );
timestampValues.put(monitor, value);
}
add(node, timestamp, timestampValues);
}
}
protected abstract void add(String node, int timestamp, Map<MonitorInfo, Integer> values);
private TopologyGraph topologyGraph = null;
public void setTopologyGraph( TopologyGraph topologyGraph ) {
this.topologyGraph = topologyGraph;
}
}