2 * Copyright IBM Corporation, 2013. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.md.statistics.manager;
10 import java.util.Collection;
11 import java.util.List;
12 import java.util.concurrent.TimeUnit;
14 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
15 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import com.google.common.base.Preconditions;
58 import com.google.common.util.concurrent.FutureCallback;
59 import com.google.common.util.concurrent.Futures;
60 import com.google.common.util.concurrent.ListenableFuture;
63 * This class handles the lifecycle of per-node statistics. It receives data
64 * from StatisticsListener, stores it in the data store and keeps track of
65 * when the data should be removed.
67 * @author avishnoi@in.ibm.com
69 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
70 private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
71 private static final int NUMBER_OF_WAIT_CYCLES = 2;
73 private final MultipartMessageManager msgManager = new MultipartMessageManager();
74 private final InstanceIdentifier<Node> targetNodeIdentifier;
75 private final FlowStatsTracker flowStats;
76 private final FlowTableStatsTracker flowTableStats;
77 private final GroupDescStatsTracker groupDescStats;
78 private final GroupStatsTracker groupStats;
79 private final MeterConfigStatsTracker meterConfigStats;
80 private final MeterStatsTracker meterStats;
81 private final NodeConnectorStatsTracker nodeConnectorStats;
82 private final QueueStatsTracker queueStats;
83 private final DataProviderService dps;
84 private final NodeRef targetNodeRef;
85 private final NodeKey targetNodeKey;
87 public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
88 final OpendaylightFlowStatisticsService flowStatsService,
89 final OpendaylightFlowTableStatisticsService flowTableStatsService,
90 final OpendaylightGroupStatisticsService groupStatsService,
91 final OpendaylightMeterStatisticsService meterStatsService,
92 final OpendaylightPortStatisticsService portStatsService,
93 final OpendaylightQueueStatisticsService queueStatsService) {
94 this.dps = Preconditions.checkNotNull(dps);
95 this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
96 this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
97 this.targetNodeRef = new NodeRef(targetNodeIdentifier);
99 final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
101 flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
102 flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
103 groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
104 groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
105 meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
106 meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
107 nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
108 queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
111 public NodeKey getTargetNodeKey() {
112 return targetNodeKey;
116 public InstanceIdentifier<Node> getNodeIdentifier() {
117 return targetNodeIdentifier;
121 public NodeRef getNodeRef() {
122 return targetNodeRef;
126 public DataModificationTransaction startDataModification() {
127 return dps.beginTransaction();
130 public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
131 if (msgManager.isExpectedTransaction(transaction, more)) {
132 groupDescStats.updateStats(list);
136 public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
137 if (msgManager.isExpectedTransaction(transaction, more)) {
138 groupStats.updateStats(list);
142 public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
143 if (msgManager.isExpectedTransaction(transaction, more)) {
144 meterConfigStats.updateStats(list);
148 public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
149 if (msgManager.isExpectedTransaction(transaction, more)) {
150 meterStats.updateStats(list);
154 public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
155 if (msgManager.isExpectedTransaction(transaction, more)) {
156 queueStats.updateStats(list);
160 public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
161 if (msgManager.isExpectedTransaction(transaction, more)) {
162 flowTableStats.updateStats(list);
166 public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
167 if (msgManager.isExpectedTransaction(transaction, more)) {
168 nodeConnectorStats.updateStats(list);
172 public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
173 final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
174 if (tableId != null) {
175 final DataModificationTransaction trans = dps.beginTransaction();
176 InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
177 .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
179 AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
180 AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
182 aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
184 logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
185 aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
187 TableBuilder tableBuilder = new TableBuilder();
188 tableBuilder.setKey(new TableKey(tableId));
189 tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
190 trans.putOperationalData(tableRef, tableBuilder.build());
196 public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
197 if (msgManager.isExpectedTransaction(transaction, more)) {
198 flowStats.updateStats(list);
202 public synchronized void updateGroupFeatures(GroupFeatures notification) {
203 final DataModificationTransaction trans = dps.beginTransaction();
205 final NodeBuilder nodeData = new NodeBuilder();
206 nodeData.setKey(targetNodeKey);
208 NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
209 GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
210 nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
212 //Update augmented data
213 nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
214 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
216 // FIXME: should we be tracking this data?
220 public synchronized void updateMeterFeatures(MeterFeatures features) {
221 final DataModificationTransaction trans = dps.beginTransaction();
223 final NodeBuilder nodeData = new NodeBuilder();
224 nodeData.setKey(targetNodeKey);
226 NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
227 MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
228 nodeMeterFeatures.setMeterFeatures(meterFeature.build());
230 //Update augmented data
231 nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
232 trans.putOperationalData(targetNodeIdentifier, nodeData.build());
234 // FIXME: should we be tracking this data?
238 public synchronized void cleanStaleStatistics() {
239 final DataModificationTransaction trans = dps.beginTransaction();
240 final long now = System.nanoTime();
242 flowStats.cleanup(trans, now);
243 groupDescStats.cleanup(trans, now);
244 groupStats.cleanup(trans, now);
245 meterConfigStats.cleanup(trans, now);
246 meterStats.cleanup(trans, now);
247 nodeConnectorStats.cleanup(trans, now);
248 queueStats.cleanup(trans, now);
249 msgManager.cleanStaleTransactionIds();
254 public synchronized void requestPeriodicStatistics() {
255 logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
257 flowTableStats.request();
259 // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
260 // comes back -- we do not have any tables anyway.
261 final Collection<TableKey> tables = flowTableStats.getTables();
262 logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
263 for (final TableKey key : tables) {
264 logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
265 flowStats.requestAggregateFlows(key);
268 flowStats.requestAllFlowsAllTables();
269 nodeConnectorStats.request();
270 groupStats.request();
271 groupDescStats.request();
272 meterStats.request();
273 meterConfigStats.request();
274 queueStats.request();
277 public synchronized void start() {
278 flowStats.start(dps);
279 groupDescStats.start(dps);
280 groupStats.start(dps);
281 meterConfigStats.start(dps);
282 meterStats.start(dps);
283 queueStats.start(dps);
285 requestPeriodicStatistics();
289 public synchronized void close() {
291 groupDescStats.close();
293 meterConfigStats.close();
297 logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
301 public void registerTransaction(final ListenableFuture<TransactionId> future) {
302 Futures.addCallback(future, new FutureCallback<TransactionId>() {
304 public void onSuccess(TransactionId result) {
305 msgManager.recordExpectedTransaction(result);
306 logger.debug("Transaction {} for node {} sent successfully", result, targetNodeKey);
310 public void onFailure(Throwable t) {
311 logger.warn("Failed to send statistics request for node {}", targetNodeKey, t);
317 public void registerTableTransaction(final ListenableFuture<TransactionId> future, final Short id) {
318 Futures.addCallback(future, new FutureCallback<TransactionId>() {
320 public void onSuccess(TransactionId result) {
321 msgManager.recordExpectedTableTransaction(result, id);
322 logger.debug("Transaction {} for node {} table {} sent successfully", result, targetNodeKey, id);
326 public void onFailure(Throwable t) {
327 logger.warn("Failed to send table statistics request for node {} table {}", targetNodeKey, id, t);