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