Merge "Move queue/meter/flow listeners into their trackers"
[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.md.statistics.manager.MultipartMessageManager.StatsRequestType;
15 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
16 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import com.google.common.base.Preconditions;
59 import com.google.common.util.concurrent.FutureCallback;
60 import com.google.common.util.concurrent.Futures;
61 import com.google.common.util.concurrent.ListenableFuture;
62
63 /**
64  * This class handles the lifecycle of per-node statistics. It receives data
65  * from StatisticsListener, stores it in the data store and keeps track of
66  * when the data should be removed.
67  *
68  * @author avishnoi@in.ibm.com
69  */
70 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
71     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
72     private static final int NUMBER_OF_WAIT_CYCLES = 2;
73
74     private final MultipartMessageManager msgManager = new MultipartMessageManager();
75     private final InstanceIdentifier<Node> targetNodeIdentifier;
76     private final FlowStatsTracker flowStats;
77     private final FlowTableStatsTracker flowTableStats;
78     private final GroupDescStatsTracker groupDescStats;
79     private final GroupStatsTracker groupStats;
80     private final MeterConfigStatsTracker meterConfigStats;
81     private final MeterStatsTracker meterStats;
82     private final NodeConnectorStatsTracker nodeConnectorStats;
83     private final QueueStatsTracker queueStats;
84     private final DataProviderService dps;
85     private final NodeRef targetNodeRef;
86     private final NodeKey targetNodeKey;
87
88     public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
89             final OpendaylightFlowStatisticsService flowStatsService,
90             final OpendaylightFlowTableStatisticsService flowTableStatsService,
91             final OpendaylightGroupStatisticsService groupStatsService,
92             final OpendaylightMeterStatisticsService meterStatsService,
93             final OpendaylightPortStatisticsService portStatsService,
94             final OpendaylightQueueStatisticsService queueStatsService) {
95         this.dps = Preconditions.checkNotNull(dps);
96         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
97         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
98         this.targetNodeRef = new NodeRef(targetNodeIdentifier);
99
100         final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
101
102         flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
103         flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
104         groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
105         groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
106         meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
107         meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
108         nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
109         queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
110     }
111
112     public NodeKey getTargetNodeKey() {
113         return targetNodeKey;
114     }
115
116     @Override
117     public InstanceIdentifier<Node> getNodeIdentifier() {
118         return targetNodeIdentifier;
119     }
120
121     @Override
122     public NodeRef getNodeRef() {
123         return targetNodeRef;
124     }
125
126     @Override
127     public DataModificationTransaction startDataModification() {
128         return dps.beginTransaction();
129     }
130
131     public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
132         if (msgManager.isExpectedTransaction(transaction, more)) {
133             groupDescStats.updateStats(list);
134         }
135     }
136
137     public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
138         if (msgManager.isExpectedTransaction(transaction, more)) {
139             groupStats.updateStats(list);
140         }
141     }
142
143     public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
144         if (msgManager.isExpectedTransaction(transaction, more)) {
145             meterConfigStats.updateStats(list);
146         }
147     }
148
149     public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
150         if (msgManager.isExpectedTransaction(transaction, more)) {
151             meterStats.updateStats(list);
152         }
153     }
154
155     public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
156         if (msgManager.isExpectedTransaction(transaction, more)) {
157             queueStats.updateStats(list);
158         }
159     }
160
161     public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
162         if (msgManager.isExpectedTransaction(transaction, more)) {
163             flowTableStats.updateStats(list);
164         }
165     }
166
167     public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
168         if (msgManager.isExpectedTransaction(transaction, more)) {
169             nodeConnectorStats.updateStats(list);
170         }
171     }
172
173     public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
174         final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
175         if (tableId != null) {
176             final DataModificationTransaction trans = dps.beginTransaction();
177             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
178                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
179
180             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
181             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
182
183             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
184
185             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
186                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
187
188             TableBuilder tableBuilder = new TableBuilder();
189             tableBuilder.setKey(new TableKey(tableId));
190             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
191             trans.putOperationalData(tableRef, tableBuilder.build());
192
193             trans.commit();
194         }
195     }
196
197     public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
198         if (msgManager.isExpectedTransaction(transaction, more)) {
199             flowStats.updateStats(list);
200         }
201     }
202
203     public synchronized void updateGroupFeatures(GroupFeatures notification) {
204         final DataModificationTransaction trans = dps.beginTransaction();
205
206         final NodeBuilder nodeData = new NodeBuilder();
207         nodeData.setKey(targetNodeKey);
208
209         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
210         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
211         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
212
213         //Update augmented data
214         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
215         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
216
217         // FIXME: should we be tracking this data?
218         trans.commit();
219     }
220
221     public synchronized void updateMeterFeatures(MeterFeatures features) {
222         final DataModificationTransaction trans = dps.beginTransaction();
223
224         final NodeBuilder nodeData = new NodeBuilder();
225         nodeData.setKey(targetNodeKey);
226
227         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
228         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
229         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
230
231         //Update augmented data
232         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
233         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
234
235         // FIXME: should we be tracking this data?
236         trans.commit();
237     }
238
239     public synchronized void cleanStaleStatistics() {
240         final DataModificationTransaction trans = dps.beginTransaction();
241         final long now = System.nanoTime();
242
243         flowStats.cleanup(trans, now);
244         groupDescStats.cleanup(trans, now);
245         groupStats.cleanup(trans, now);
246         meterConfigStats.cleanup(trans, now);
247         meterStats.cleanup(trans, now);
248         nodeConnectorStats.cleanup(trans, now);
249         queueStats.cleanup(trans, now);
250         msgManager.cleanStaleTransactionIds();
251
252         trans.commit();
253     }
254
255     public synchronized void requestPeriodicStatistics() {
256         logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
257
258         flowTableStats.request();
259
260         // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
261         //        comes back -- we do not have any tables anyway.
262         final Collection<TableKey> tables = flowTableStats.getTables();
263         logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
264         for (final TableKey key : tables) {
265             logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
266             flowStats.requestAggregateFlows(key);
267         }
268
269         flowStats.requestAllFlowsAllTables();
270         nodeConnectorStats.request();
271         groupStats.request();
272         groupDescStats.request();
273         meterStats.request();
274         meterConfigStats.request();
275         queueStats.request();
276     }
277
278     public synchronized void start() {
279         flowStats.start(dps);
280         groupDescStats.start(dps);
281         groupStats.start(dps);
282         meterConfigStats.start(dps);
283         meterStats.start(dps);
284         queueStats.start(dps);
285
286         requestPeriodicStatistics();
287     }
288
289     @Override
290     public synchronized void close() {
291         flowStats.close();
292         groupDescStats.close();
293         groupStats.close();
294         meterConfigStats.close();
295         meterStats.close();
296         queueStats.close();
297
298         logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
299     }
300
301     @Override
302     public void registerTransaction(final ListenableFuture<TransactionId> future, final StatsRequestType type) {
303         Futures.addCallback(future, new FutureCallback<TransactionId>() {
304             @Override
305             public void onSuccess(TransactionId result) {
306                 msgManager.recordExpectedTransaction(result, type);
307                 logger.debug("Transaction {} for node {} sent successfully", result, targetNodeKey);
308             }
309
310             @Override
311             public void onFailure(Throwable t) {
312                 logger.warn("Failed to send statistics request for node {}", targetNodeKey, t);
313             }
314         });
315     }
316
317     @Override
318     public void registerTableTransaction(final ListenableFuture<TransactionId> future, final Short id) {
319         Futures.addCallback(future, new FutureCallback<TransactionId>() {
320             @Override
321             public void onSuccess(TransactionId result) {
322                 msgManager.recordExpectedTableTransaction(result, StatsRequestType.AGGR_FLOW, id);
323                 logger.debug("Transaction {} for node {} table {} sent successfully", result, targetNodeKey, id);
324             }
325
326             @Override
327             public void onFailure(Throwable t) {
328                 logger.warn("Failed to send table statistics request for node {} table {}", targetNodeKey, id, t);
329             }
330         });
331     }
332 }