Jian Li

Add resource name into MetricsDatabase, handle exception gracefully

Change-Id: Icf19965a0fcbfd9696c42b12c32441fd3b161734
......@@ -30,6 +30,13 @@ public interface MetricsDatabase {
String metricName();
/**
* Returns the resource name of this database.
*
* @return resource name
*/
String resourceName();
/**
* Update metric value by specifying metric type.
*
* @param metricType metric type (e.g., load, usage, etc.)
......@@ -138,6 +145,14 @@ public interface MetricsDatabase {
Builder withMetricName(String metricName);
/**
* Sets the resource name.
*
* @param resourceName resource name
* @return builder object
*/
Builder withResourceName(String resourceName);
/**
* Add a new metric to be monitored.
*
* @param metricType control metric type
......
......@@ -77,6 +77,8 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterCommunicationService communicationService;
private static final String DEFAULT_RESOURCE = "default";
private static final Set RESOURCE_TYPE_SET =
ImmutableSet.of(Type.CONTROL_MESSAGE, Type.DISK, Type.NETWORK);
......@@ -96,6 +98,8 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService {
private static final String METRIC_TYPE_NULL = "Control metric type cannot be null";
Set<Map<ControlMetricType, Double>> debugSets = Sets.newHashSet();
private static final Serializer SERIALIZER = Serializer
.using(new KryoNamespace.Builder()
.register(KryoNamespaces.API)
......@@ -107,8 +111,8 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService {
@Activate
public void activate() {
cpuMetrics = genMDbBuilder(Type.CPU, CPU_METRICS);
memoryMetrics = genMDbBuilder(Type.MEMORY, MEMORY_METRICS);
cpuMetrics = genMDbBuilder(DEFAULT_RESOURCE, Type.CPU, CPU_METRICS);
memoryMetrics = genMDbBuilder(DEFAULT_RESOURCE, Type.MEMORY, MEMORY_METRICS);
controlMessageMap = Maps.newConcurrentMap();
diskMetricsMap = Maps.newConcurrentMap();
networkMetricsMap = Maps.newConcurrentMap();
......@@ -170,7 +174,7 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService {
if (ctrlMsgBuf.get(deviceId.get()).keySet()
.containsAll(CONTROL_MESSAGE_METRICS)) {
updateControlMessages(ctrlMsgBuf.get(deviceId.get()), deviceId.get());
ctrlMsgBuf.get(deviceId.get()).clear();
ctrlMsgBuf.get(deviceId.get());
}
}
} else {
......@@ -304,31 +308,34 @@ public class ControlPlaneMonitor implements ControlPlaneMonitorService {
return ImmutableSet.of();
}
private MetricsDatabase genMDbBuilder(Type resourceType,
private MetricsDatabase genMDbBuilder(String resourceName,
Type resourceType,
Set<ControlMetricType> metricTypes) {
MetricsDatabase.Builder builder = new DefaultMetricsDatabase.Builder();
builder.withMetricName(resourceType.toString());
builder.withResourceName(resourceName);
metricTypes.forEach(type -> builder.addMetricType(type.toString()));
return builder.build();
}
private void updateNetworkMetrics(Map<ControlMetricType, Double> metricMap,
String resName) {
networkMetricsMap.putIfAbsent(resName,
genMDbBuilder(Type.NETWORK, NETWORK_METRICS));
networkMetricsMap.putIfAbsent(resName, genMDbBuilder(resName,
Type.NETWORK, NETWORK_METRICS));
networkMetricsMap.get(resName).updateMetrics(convertMap(metricMap));
}
private void updateDiskMetrics(Map<ControlMetricType, Double> metricMap,
String resName) {
diskMetricsMap.putIfAbsent(resName, genMDbBuilder(Type.DISK, DISK_METRICS));
diskMetricsMap.putIfAbsent(resName, genMDbBuilder(resName,
Type.DISK, DISK_METRICS));
diskMetricsMap.get(resName).updateMetrics(convertMap(metricMap));
}
private void updateControlMessages(Map<ControlMetricType, Double> metricMap,
DeviceId devId) {
controlMessageMap.putIfAbsent(devId,
genMDbBuilder(Type.CONTROL_MESSAGE, CONTROL_MESSAGE_METRICS));
controlMessageMap.putIfAbsent(devId, genMDbBuilder(devId.toString(),
Type.CONTROL_MESSAGE, CONTROL_MESSAGE_METRICS));
controlMessageMap.get(devId).updateMetrics(convertMap(metricMap));
}
......
......@@ -26,6 +26,8 @@ import org.rrd4j.core.RrdBackendFactory;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdDef;
import org.rrd4j.core.Sample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
......@@ -43,7 +45,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
* An implementation of control plane metrics back-end database.
*/
public final class DefaultMetricsDatabase implements MetricsDatabase {
private final Logger log = LoggerFactory.getLogger(getClass());
private String metricName;
private String resourceName;
private RrdDb rrdDb;
private Sample sample;
private static final long SECONDS_OF_DAY = 60L * 60L * 24L;
......@@ -60,8 +65,9 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
* @param metricName metric name
* @param rrdDb round robin database
*/
private DefaultMetricsDatabase(String metricName, RrdDb rrdDb) {
private DefaultMetricsDatabase(String metricName, String resourceName, RrdDb rrdDb) {
this.metricName = metricName;
this.resourceName = resourceName;
this.rrdDb = rrdDb;
}
......@@ -71,6 +77,11 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
}
@Override
public String resourceName() {
return this.resourceName;
}
@Override
public void updateMetric(String metricType, double value) {
updateMetric(metricType, value, System.currentTimeMillis() / 1000L);
}
......@@ -83,7 +94,7 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
sample.setValue(metricType, value);
sample.update();
} catch (IOException e) {
e.printStackTrace();
log.error("Failed to update metric value due to {}", e.getMessage());
}
}
......@@ -106,7 +117,7 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
});
sample.update();
} catch (IOException e) {
e.printStackTrace();
log.error("Failed to update metric values due to {}", e.getMessage());
}
}
......@@ -116,10 +127,10 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
checkArgument(rrdDb.containsDs(metricType), NON_EXIST_METRIC);
return rrdDb.getDatasource(metricType).getLastValue();
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric value due to {}", e.getMessage());
return 0D;
}
}
@Override
public double[] recentMetrics(String metricType, int duration, TimeUnit unit) {
......@@ -130,12 +141,15 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
if (checkTimeRange(startTime, endTime)) {
FetchRequest fr = rrdDb.createFetchRequest(CONSOL_FUNCTION, startTime, endTime);
return arrangeDataPoints(fr.fetchData().getValues(metricType));
} else {
log.warn("Data projection is out-of-range");
return new double[0];
}
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric values due to {}", e.getMessage());
return new double[0];
}
}
@Override
public double minMetric(String metricType) {
......@@ -145,10 +159,10 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
long startTime = endTime - SECONDS_OF_DAY + 1;
return minMetric(metricType, startTime, endTime);
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric value due to {}", e.getMessage());
return 0D;
}
}
@Override
public double maxMetric(String metricType) {
......@@ -158,10 +172,10 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
long startTime = endTime - SECONDS_OF_DAY;
return maxMetric(metricType, startTime, endTime);
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric value due to {}", e.getMessage());
return 0D;
}
}
@Override
public double[] metrics(String metricType) {
......@@ -171,10 +185,10 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
long startTime = endTime - SECONDS_OF_DAY;
return metrics(metricType, startTime, endTime);
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric values due to {}", e.getMessage());
return new double[0];
}
}
@Override
public double[] metrics(String metricType, long startTime, long endTime) {
......@@ -183,23 +197,26 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
if (checkTimeRange(startTime, endTime)) {
FetchRequest fr = rrdDb.createFetchRequest(CONSOL_FUNCTION, startTime, endTime);
return arrangeDataPoints(fr.fetchData().getValues(metricType));
} else {
log.warn("Data projection is out-of-range");
return new double[0];
}
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain metric values due to {}", e.getMessage());
return new double[0];
}
}
@Override
public long lastUpdate(String metricType) {
try {
checkArgument(rrdDb.containsDs(metricType), NON_EXIST_METRIC);
rrdDb.getLastUpdateTime();
return rrdDb.getLastUpdateTime();
} catch (IOException e) {
e.printStackTrace();
}
log.error("Failed to obtain last update time due to {}", e.getMessage());
return 0L;
}
}
// try to check whether projected time range is within a day
private boolean checkTimeRange(long startTime, long endTime) {
......@@ -242,12 +259,15 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
private static final int STEP_VALUE = 1;
private static final int ROW_VALUE = 60 * 24;
private static final String METRIC_NAME_MSG = "Must specify a metric name.";
private static final String RESOURCE_NAME_MSG = "Must specify a resource name.";
private static final String METRIC_TYPE_MSG = "Must supply at least a metric type.";
private static final String SPLITTER = "_";
private RrdDb rrdDb;
private RrdDef rrdDef;
private List<DsDef> dsDefs;
private String metricName;
private String resourceName;
public Builder() {
// initialize data source definition list
......@@ -255,11 +275,14 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
}
@Override
public Builder withMetricName(String metricName) {
this.metricName = metricName;
public Builder withMetricName(String metric) {
this.metricName = metric;
return this;
}
// define the resolution of monitored metrics
rrdDef = new RrdDef(DB_PATH + "_" + metricName, RESOLUTION_IN_SECOND);
@Override
public MetricsDatabase.Builder withResourceName(String resource) {
this.resourceName = resource;
return this;
}
......@@ -272,8 +295,13 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
@Override
public MetricsDatabase build() {
checkNotNull(metricName, METRIC_NAME_MSG);
checkNotNull(resourceName, RESOURCE_NAME_MSG);
checkArgument(dsDefs.size() != 0, METRIC_TYPE_MSG);
// define the resolution of monitored metrics
rrdDef = new RrdDef(DB_PATH + SPLITTER + metricName +
SPLITTER + resourceName, RESOLUTION_IN_SECOND);
try {
DsDef[] dsDefArray = new DsDef[dsDefs.size()];
IntStream.range(0, dsDefs.size()).forEach(i -> dsDefArray[i] = dsDefs.get(i));
......@@ -292,7 +320,7 @@ public final class DefaultMetricsDatabase implements MetricsDatabase {
e.printStackTrace();
}
return new DefaultMetricsDatabase(metricName, rrdDb);
return new DefaultMetricsDatabase(metricName, resourceName, rrdDb);
}
private DsDef defineSchema(String metricType) {
......
......@@ -15,12 +15,18 @@
*/
package org.onosproject.cpman.impl;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.cpman.ControlMetricType;
import org.onosproject.cpman.ControlResource;
import org.onosproject.cpman.MetricsDatabase;
import org.onosproject.net.DeviceId;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.is;
......@@ -34,9 +40,11 @@ public class MetricsDatabaseTest {
private MetricsDatabase mdb;
private static final String CPU_METRIC = "cpu";
private static final String CPU_LOAD = "load";
private static final String DEFAULT_RES = "resource";
private static final String MEMORY_METRIC = "memory";
private static final String MEMORY_FREE_PERC = "freePerc";
private static final String MEMORY_USED_PERC = "usedPerc";
private Map<DeviceId, MetricsDatabase> devMetricsMap;
/**
* Initializes metrics database instance.
......@@ -45,6 +53,7 @@ public class MetricsDatabaseTest {
public void setUp() {
mdb = new DefaultMetricsDatabase.Builder()
.withMetricName(CPU_METRIC)
.withResourceName(DEFAULT_RES)
.addMetricType(CPU_LOAD)
.build();
}
......@@ -114,6 +123,7 @@ public class MetricsDatabaseTest {
public void testMultipleMetrics() {
MetricsDatabase multiMdb = new DefaultMetricsDatabase.Builder()
.withMetricName(MEMORY_METRIC)
.withResourceName(DEFAULT_RES)
.addMetricType(MEMORY_FREE_PERC)
.addMetricType(MEMORY_USED_PERC)
.build();
......@@ -126,4 +136,51 @@ public class MetricsDatabaseTest {
assertThat(30D, is(multiMdb.recentMetric(MEMORY_FREE_PERC)));
assertThat(70D, is(multiMdb.recentMetric(MEMORY_USED_PERC)));
}
/**
* Tests device metrics map update and query.
*/
@Test
public void testDeviceMetricsMap() {
ControlResource.Type type = ControlResource.Type.CONTROL_MESSAGE;
DeviceId devId1 = DeviceId.deviceId("of:0000000000000101");
DeviceId devId2 = DeviceId.deviceId("of:0000000000000102");
devMetricsMap = Maps.newHashMap();
Set<DeviceId> devices = ImmutableSet.of(devId1, devId2);
devices.forEach(dev ->
devMetricsMap.putIfAbsent(dev,
genMDbBuilder(type, ControlResource.CONTROL_MESSAGE_METRICS)
.withResourceName(dev.toString())
.build()));
Map<String, Double> metrics1 = new HashMap<>();
ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType ->
metrics1.putIfAbsent(msgType.toString(), 10D));
Map<String, Double> metrics2 = new HashMap<>();
ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType ->
metrics2.putIfAbsent(msgType.toString(), 20D));
devMetricsMap.get(devId1).updateMetrics(metrics1);
devMetricsMap.get(devId2).updateMetrics(metrics2);
ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType ->
assertThat(10D, is(devMetricsMap.get(devId1).recentMetric(msgType.toString())))
);
ControlResource.CONTROL_MESSAGE_METRICS.forEach(msgType ->
assertThat(20D, is(devMetricsMap.get(devId2).recentMetric(msgType.toString())))
);
}
private MetricsDatabase.Builder genMDbBuilder(ControlResource.Type resourceType,
Set<ControlMetricType> metricTypes) {
MetricsDatabase.Builder builder = new DefaultMetricsDatabase.Builder();
builder.withMetricName(resourceType.toString());
metricTypes.forEach(type -> builder.addMetricType(type.toString()));
return builder;
}
}
......
......@@ -141,7 +141,7 @@ public class OpenFlowControlMessageAggregator implements Runnable {
* @return count value
*/
private long getCount(OFType type) {
return (long) countMeterMap.get(type).getOneMinuteRate() *
EXECUTE_PERIOD_IN_SECOND;
return (long) (countMeterMap.get(type).getOneMinuteRate()
* EXECUTE_PERIOD_IN_SECOND);
}
}
......