d62b680e1466c89d88180b51b0d89a97b2120602
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / NodeStatisticsHandler.java
1 /*
2  * Copyright IBM Corporation, 2013.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.statistics.manager;
9
10 import java.util.Collection;
11 import java.util.List;
12 import java.util.concurrent.TimeUnit;
13
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;
56
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;
61
62 /**
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.
66  *
67  * @author avishnoi@in.ibm.com
68  */
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;
72
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;
86
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);
98
99         final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
100
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);
109     }
110
111     public NodeKey getTargetNodeKey() {
112         return targetNodeKey;
113     }
114
115     @Override
116     public InstanceIdentifier<Node> getNodeIdentifier() {
117         return targetNodeIdentifier;
118     }
119
120     @Override
121     public NodeRef getNodeRef() {
122         return targetNodeRef;
123     }
124
125     @Override
126     public DataModificationTransaction startDataModification() {
127         return dps.beginTransaction();
128     }
129
130     public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
131         if (msgManager.isExpectedTransaction(transaction, more)) {
132             groupDescStats.updateStats(list);
133         }
134     }
135
136     public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
137         if (msgManager.isExpectedTransaction(transaction, more)) {
138             groupStats.updateStats(list);
139         }
140     }
141
142     public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
143         if (msgManager.isExpectedTransaction(transaction, more)) {
144             meterConfigStats.updateStats(list);
145         }
146     }
147
148     public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
149         if (msgManager.isExpectedTransaction(transaction, more)) {
150             meterStats.updateStats(list);
151         }
152     }
153
154     public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
155         if (msgManager.isExpectedTransaction(transaction, more)) {
156             queueStats.updateStats(list);
157         }
158     }
159
160     public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
161         if (msgManager.isExpectedTransaction(transaction, more)) {
162             flowTableStats.updateStats(list);
163         }
164     }
165
166     public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
167         if (msgManager.isExpectedTransaction(transaction, more)) {
168             nodeConnectorStats.updateStats(list);
169         }
170     }
171
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();
178
179             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
180             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
181
182             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
183
184             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
185                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
186
187             TableBuilder tableBuilder = new TableBuilder();
188             tableBuilder.setKey(new TableKey(tableId));
189             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
190             trans.putOperationalData(tableRef, tableBuilder.build());
191
192             trans.commit();
193         }
194     }
195
196     public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
197         if (msgManager.isExpectedTransaction(transaction, more)) {
198             flowStats.updateStats(list);
199         }
200     }
201
202     public synchronized void updateGroupFeatures(GroupFeatures notification) {
203         final DataModificationTransaction trans = dps.beginTransaction();
204
205         final NodeBuilder nodeData = new NodeBuilder();
206         nodeData.setKey(targetNodeKey);
207
208         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
209         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
210         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
211
212         //Update augmented data
213         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
214         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
215
216         // FIXME: should we be tracking this data?
217         trans.commit();
218     }
219
220     public synchronized void updateMeterFeatures(MeterFeatures features) {
221         final DataModificationTransaction trans = dps.beginTransaction();
222
223         final NodeBuilder nodeData = new NodeBuilder();
224         nodeData.setKey(targetNodeKey);
225
226         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
227         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
228         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
229
230         //Update augmented data
231         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
232         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
233
234         // FIXME: should we be tracking this data?
235         trans.commit();
236     }
237
238     public synchronized void cleanStaleStatistics() {
239         final DataModificationTransaction trans = dps.beginTransaction();
240         final long now = System.nanoTime();
241
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();
250
251         trans.commit();
252     }
253
254     public synchronized void requestPeriodicStatistics() {
255         logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
256
257         flowTableStats.request();
258
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);
266         }
267
268         flowStats.requestAllFlowsAllTables();
269         nodeConnectorStats.request();
270         groupStats.request();
271         groupDescStats.request();
272         meterStats.request();
273         meterConfigStats.request();
274         queueStats.request();
275     }
276
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);
284
285         requestPeriodicStatistics();
286     }
287
288     @Override
289     public synchronized void close() {
290         flowStats.close();
291         groupDescStats.close();
292         groupStats.close();
293         meterConfigStats.close();
294         meterStats.close();
295         queueStats.close();
296
297         logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
298     }
299
300     @Override
301     public void registerTransaction(final ListenableFuture<TransactionId> future) {
302         Futures.addCallback(future, new FutureCallback<TransactionId>() {
303             @Override
304             public void onSuccess(TransactionId result) {
305                 msgManager.recordExpectedTransaction(result);
306                 logger.debug("Transaction {} for node {} sent successfully", result, targetNodeKey);
307             }
308
309             @Override
310             public void onFailure(Throwable t) {
311                 logger.warn("Failed to send statistics request for node {}", targetNodeKey, t);
312             }
313         });
314     }
315
316     @Override
317     public void registerTableTransaction(final ListenableFuture<TransactionId> future, final Short id) {
318         Futures.addCallback(future, new FutureCallback<TransactionId>() {
319             @Override
320             public void onSuccess(TransactionId result) {
321                 msgManager.recordExpectedTableTransaction(result, id);
322                 logger.debug("Transaction {} for node {} table {} sent successfully", result, targetNodeKey, id);
323             }
324
325             @Override
326             public void onFailure(Throwable t) {
327                 logger.warn("Failed to send table statistics request for node {} table {}", targetNodeKey, id, t);
328             }
329         });
330     }
331 }