Merge "Bug 1073: Added Transaction Chain support to InMemoryDataTreeModification."
[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.List;
11 import java.util.Timer;
12 import java.util.TimerTask;
13 import java.util.concurrent.TimeUnit;
14
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
60 /**
61  * This class handles the lifecycle of per-node statistics. It receives data
62  * from StatisticsListener, stores it in the data store and keeps track of
63  * when the data should be removed.
64  *
65  * @author avishnoi@in.ibm.com
66  */
67 public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
68     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
69
70     private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15);
71     private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5);
72     private static final int NUMBER_OF_WAIT_CYCLES = 2;
73
74     private final MultipartMessageManager msgManager;
75     private final StatisticsRequestScheduler srScheduler;
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             final StatisticsRequestScheduler srScheduler) {
108         this.dps = Preconditions.checkNotNull(dps);
109         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
110         this.srScheduler = Preconditions.checkNotNull(srScheduler);
111         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
112         this.targetNodeRef = new NodeRef(targetNodeIdentifier);
113
114         final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
115
116         msgManager = new MultipartMessageManager(lifetimeNanos);
117         flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this);
118         flowStats = new FlowStatsTracker(flowStatsService, this, flowTableStats);
119         groupDescStats = new GroupDescStatsTracker(groupStatsService, this);
120         groupStats = new GroupStatsTracker(groupStatsService, this);
121         meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this);
122         meterStats = new MeterStatsTracker(meterStatsService, this);
123         nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this);
124         queueStats = new QueueStatsTracker(queueStatsService, this);
125     }
126
127     public NodeKey getTargetNodeKey() {
128         return targetNodeKey;
129     }
130
131     @Override
132     public InstanceIdentifier<Node> getNodeIdentifier() {
133         return targetNodeIdentifier;
134     }
135
136     @Override
137     public NodeRef getNodeRef() {
138         return targetNodeRef;
139     }
140
141     @Override
142     public DataModificationTransaction startDataModification() {
143         DataModificationTransaction dmt = dps.beginTransaction();
144         dmt.registerListener(this.srScheduler);
145         return dmt;
146     }
147
148     public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
149         if (msgManager.isExpectedTransaction(transaction)) {
150             groupDescStats.updateStats(list);
151         }
152     }
153
154     public synchronized void updateGroupStats(TransactionAware transaction, List<GroupStats> list) {
155         if (msgManager.isExpectedTransaction(transaction)) {
156             groupStats.updateStats(list);
157         }
158     }
159
160     public synchronized void updateMeterConfigStats(TransactionAware transaction, List<MeterConfigStats> list) {
161         if (msgManager.isExpectedTransaction(transaction)) {
162             meterConfigStats.updateStats(list);
163         }
164     }
165
166     public synchronized void updateMeterStats(TransactionAware transaction, List<MeterStats> list) {
167         if (msgManager.isExpectedTransaction(transaction)) {
168             meterStats.updateStats(list);
169         }
170     }
171
172     public synchronized void updateQueueStats(TransactionAware transaction, List<QueueIdAndStatisticsMap> list) {
173         if (msgManager.isExpectedTransaction(transaction)) {
174             queueStats.updateStats(list);
175         }
176     }
177
178     public synchronized void updateFlowTableStats(TransactionAware transaction, List<FlowTableAndStatisticsMap> list) {
179         if (msgManager.isExpectedTransaction(transaction)) {
180             flowTableStats.updateStats(list);
181         }
182     }
183
184     public synchronized void updateNodeConnectorStats(TransactionAware transaction, List<NodeConnectorStatisticsAndPortNumberMap> list) {
185         if (msgManager.isExpectedTransaction(transaction)) {
186             nodeConnectorStats.updateStats(list);
187         }
188     }
189
190     public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
191         final Short tableId = msgManager.isExpectedTableTransaction(transaction);
192         if (tableId != null) {
193             final DataModificationTransaction trans = this.startDataModification();
194             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
195                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
196
197             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
198             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
199
200             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
201
202             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
203                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
204
205             TableBuilder tableBuilder = new TableBuilder();
206             tableBuilder.setKey(new TableKey(tableId));
207             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
208             trans.putOperationalData(tableRef, tableBuilder.build());
209
210             trans.commit();
211         }
212     }
213
214     public synchronized void updateFlowStats(TransactionAware transaction, List<FlowAndStatisticsMapList> list) {
215         if (msgManager.isExpectedTransaction(transaction)) {
216             flowStats.updateStats(list);
217         }
218     }
219
220     public synchronized void updateGroupFeatures(GroupFeatures notification) {
221         final DataModificationTransaction trans = this.startDataModification();
222
223         final NodeBuilder nodeData = new NodeBuilder();
224         nodeData.setKey(targetNodeKey);
225
226         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
227         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
228         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
229
230         //Update augmented data
231         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.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 updateMeterFeatures(MeterFeatures features) {
239         final DataModificationTransaction trans = this.startDataModification();
240
241         final NodeBuilder nodeData = new NodeBuilder();
242         nodeData.setKey(targetNodeKey);
243
244         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
245         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
246         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
247
248         //Update augmented data
249         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
250         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
251
252         // FIXME: should we be tracking this data?
253         trans.commit();
254     }
255
256     public synchronized void cleanStaleStatistics() {
257         final DataModificationTransaction trans = this.startDataModification();
258
259         flowStats.cleanup(trans);
260         groupDescStats.cleanup(trans);
261         groupStats.cleanup(trans);
262         meterConfigStats.cleanup(trans);
263         meterStats.cleanup(trans);
264         nodeConnectorStats.cleanup(trans);
265         queueStats.cleanup(trans);
266         msgManager.cleanStaleTransactionIds();
267
268         trans.commit();
269     }
270
271     public synchronized void requestPeriodicStatistics() {
272         logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
273
274         this.srScheduler.addRequestToSchedulerQueue(flowTableStats);
275
276         this.srScheduler.addRequestToSchedulerQueue(flowStats);
277         
278         this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats);
279         
280         this.srScheduler.addRequestToSchedulerQueue(groupStats);
281         
282         this.srScheduler.addRequestToSchedulerQueue(groupDescStats);
283         
284         this.srScheduler.addRequestToSchedulerQueue(meterStats);
285         
286         this.srScheduler.addRequestToSchedulerQueue(meterConfigStats);
287         
288         this.srScheduler.addRequestToSchedulerQueue(queueStats);
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         //Clean up queued statistics request from scheduler queue 
317         srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef());
318
319         logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
320     }
321
322     @Override
323     public void registerTransaction(TransactionId id) {
324         msgManager.recordExpectedTransaction(id);
325         logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
326     }
327
328     @Override
329     public void registerTableTransaction(final TransactionId id, final Short table) {
330         msgManager.recordExpectedTableTransaction(id, table);
331         logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);
332     }
333 }