package jvmmonitor.agent.module; import java.util.List; import java.util.Map; import jvmmonitor.agent.Util; import jvmmonitor.agent.monitor.MonitorItem; import lombok.Getter; import sun.jvmstat.monitor.LongMonitor; import sun.jvmstat.monitor.MonitorException; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * Created by peiliping on 16-12-21. */ public abstract class AbstractModule implements IModule { public static AbstractModule build(Class<? extends AbstractModule> clazz, String moduleName, MonitorItem item) throws Exception { return clazz.getConstructor(String.class, MonitorItem.class).newInstance(moduleName, item); } @Getter protected String moduleName; protected long precision = 0; protected String[] noChangeMetricNames; protected int metricValuesNum = 2; private final Map<String, String> metricsName = Maps.newHashMap(); protected final Map<String, LongMonitor> monitors = Maps.newHashMap(); protected final Map<String, long[][]> temporaryData = Maps.newHashMap(); protected int tempDataSize = 2; protected int temporarySeq = 0; protected final Map<String, long[][]> resultDataRBuffer = Maps.newHashMap(); protected int resultDataSize = 64; protected int dataWSeq = 0; protected int dataRSeq = 0; public AbstractModule(String moduleName, MonitorItem item) { this.moduleName = moduleName; this.precision = Util.getLongValueFromMonitoredVm(item.getMonitoredVm(), "sun.os.hrt.frequency", 1000000000) / 1000000; } protected boolean addMetric(MonitorItem item, String metricName, String perfDataName) { try { this.metricsName.put(metricName, perfDataName); LongMonitor lm = (LongMonitor) item.getMonitoredVm().findByName(perfDataName); if (lm != null) { this.monitors.put(metricName, lm); long ts[][] = new long[tempDataSize][2]; for (int i = 0; i < tempDataSize; i++) { ts[i] = new long[] {0, 0}; } this.temporaryData.put(metricName, ts); return true; } } catch (MonitorException e) { e.printStackTrace(); } return false; } protected int cursor4TempData() { return this.temporarySeq & (this.tempDataSize - 1); } protected int lastCursor4TempData(int n) { return (this.temporarySeq - n) & (this.tempDataSize - 1); } protected Long getOriginVal(String metric) { long[][] temp = this.temporaryData.get(metric); return temp != null ? temp[lastCursor4TempData(1)][1] : null; } protected Long getDeltaVal(String metric) { long[][] temp = this.temporaryData.get(metric); if (temp == null) return null; return this.temporarySeq > 1 ? (temp[lastCursor4TempData(1)][1] - temp[lastCursor4TempData(2)][1]) : null; } protected Long handleTimePrecision(Long time) { return (time != null) ? time / precision : null; } protected int cursor4Data() { return this.dataWSeq & (this.resultDataSize - 1); } protected int nextCursor4Data(int n) { return (this.dataRSeq + n) & (this.resultDataSize - 1); } private int dataLength() { return this.dataWSeq - this.dataRSeq; } public void monitor(long timestamp) { int cr = cursor4TempData(); for (Map.Entry<String, LongMonitor> entry : this.monitors.entrySet()) { this.temporaryData.get(entry.getKey())[cr][0] = timestamp; this.temporaryData.get(entry.getKey())[cr][1] = entry.getValue().longValue(); } this.temporarySeq++; } protected int continuousNoChange = 0; protected boolean atLeastOnce4NoChange = false; public boolean changed() { if (this.noChangeMetricNames == null) { this.continuousNoChange = 0; return true; } else { for (String ncmn : this.noChangeMetricNames) { Long t = getDeltaVal(ncmn); if (t != null && t != 0) { this.continuousNoChange = 0; return true; } } } this.continuousNoChange++; if (this.atLeastOnce4NoChange && this.continuousNoChange >= 10) { this.continuousNoChange = 0; return true; } return false; } protected void commit() { this.dataWSeq++; } protected void store(String key, long timestamp, Long... values) { if (values == null) return; long[][] temp = this.resultDataRBuffer.get(key); if (temp == null) { long ts[][] = new long[this.resultDataSize][this.metricValuesNum]; for (int i = 0; i < this.resultDataSize; i++) { ts[i] = new long[this.metricValuesNum]; } this.resultDataRBuffer.put(key, ts); temp = ts; } long[] item = temp[cursor4Data()]; item[0] = timestamp; for (int i = 0; i < values.length; i++) { item[i + 1] = (values[i] == null ? 0 : values[i]); } } private final Map<String, long[][]> pullBuffer = Maps.newHashMap(); protected boolean filterZeroValue = false; public Map<String, long[][]> pullData() { this.pullBuffer.clear(); if (dataLength() == 0) return this.pullBuffer; for (Map.Entry<String, long[][]> item : this.resultDataRBuffer.entrySet()) { if (this.filterZeroValue) { List<long[]> ts = Lists.newArrayList(); for (int i = 0; i < dataLength(); i++) { if (item.getValue()[nextCursor4Data(i)][1] == 0) { continue; } ts.add(item.getValue()[nextCursor4Data(i)]); } this.pullBuffer.put(item.getKey(), ts.toArray(new long[ts.size()][this.metricValuesNum])); } else { long ts[][] = new long[dataLength()][this.metricValuesNum]; for (int i = 0; i < dataLength(); i++) { ts[i] = item.getValue()[nextCursor4Data(i)]; } this.pullBuffer.put(item.getKey(), ts); } } this.dataRSeq = this.dataWSeq; return this.pullBuffer; } protected boolean valid = true; public boolean valid() { return valid; } }