Merge "Move flow comparison methods into utility class"
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / NodeStatisticsAger.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.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.concurrent.TimeUnit;
16
17 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
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.FlowCapableNodeConnector;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 import com.google.common.base.Preconditions;
90
91 /**
92  * Main responsibility of this class to clean up all the stale statistics data
93  * associated to Flow,Meter,Group,Queue.
94  * @author avishnoi@in.ibm.com
95  *
96  */
97 public class NodeStatisticsAger {
98     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsAger.class);
99     private static final int NUMBER_OF_WAIT_CYCLES = 2;
100
101     private final Map<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
102     private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
103     private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
104     private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
105     private final InstanceIdentifier<Node> targetNodeIdentifier;
106     private final StatisticsProvider statisticsProvider;
107     private final NodeKey targetNodeKey;
108
109     public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){
110         this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider);
111         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
112         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
113     }
114
115     public class FlowEntry {
116         private final Short tableId;
117         private final Flow flow;
118
119         public FlowEntry(Short tableId, Flow flow){
120             this.tableId = tableId;
121             this.flow = flow;
122         }
123
124         public Short getTableId() {
125             return tableId;
126         }
127
128         public Flow getFlow() {
129             return flow;
130         }
131
132         @Override
133         public int hashCode() {
134             final int prime = 31;
135             int result = 1;
136             result = prime * result + getOuterType().hashCode();
137             result = prime * result + ((flow == null) ? 0 : flow.hashCode());
138             result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
139             return result;
140         }
141
142         @Override
143         public boolean equals(Object obj) {
144             if (this == obj)
145                 return true;
146             if (obj == null)
147                 return false;
148             if (getClass() != obj.getClass())
149                 return false;
150             FlowEntry other = (FlowEntry) obj;
151             if (!getOuterType().equals(other.getOuterType()))
152                 return false;
153             if (flow == null) {
154                 if (other.flow != null)
155                     return false;
156             } else if (!flow.equals(other.flow))
157                 return false;
158             if (tableId == null) {
159                 if (other.tableId != null)
160                     return false;
161             } else if (!tableId.equals(other.tableId))
162                 return false;
163             return true;
164         }
165
166         private NodeStatisticsAger getOuterType() {
167             return NodeStatisticsAger.this;
168         }
169     }
170
171     private static final class QueueEntry{
172         private final NodeConnectorId nodeConnectorId;
173         private final QueueId queueId;
174         public QueueEntry(NodeConnectorId ncId, QueueId queueId){
175             this.nodeConnectorId = ncId;
176             this.queueId = queueId;
177         }
178         public NodeConnectorId getNodeConnectorId() {
179             return nodeConnectorId;
180         }
181         public QueueId getQueueId() {
182             return queueId;
183         }
184         @Override
185         public int hashCode() {
186             final int prime = 31;
187             int result = 1;
188             result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
189             result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
190             return result;
191         }
192         @Override
193         public boolean equals(Object obj) {
194             if (this == obj) {
195                 return true;
196             }
197             if (obj == null) {
198                 return false;
199             }
200             if (!(obj instanceof QueueEntry)) {
201                 return false;
202             }
203             QueueEntry other = (QueueEntry) obj;
204             if (nodeConnectorId == null) {
205                 if (other.nodeConnectorId != null) {
206                     return false;
207                 }
208             } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
209                 return false;
210             }
211             if (queueId == null) {
212                 if (other.queueId != null) {
213                     return false;
214                 }
215             } else if (!queueId.equals(other.queueId)) {
216                 return false;
217             }
218             return true;
219         }
220     }
221
222     public NodeKey getTargetNodeKey() {
223         return targetNodeKey;
224     }
225
226     public synchronized void updateGroupDescStats(List<GroupDescStats> list){
227         final Long expiryTime = getExpiryTime();
228         final DataModificationTransaction trans = statisticsProvider.startChange();
229
230         for (GroupDescStats groupDescStats : list) {
231             GroupBuilder groupBuilder = new GroupBuilder();
232             GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
233             groupBuilder.setKey(groupKey);
234
235             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
236                                                                                         .augmentation(FlowCapableNode.class)
237                                                                                         .child(Group.class,groupKey).toInstance();
238
239             NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
240             GroupDescBuilder stats = new GroupDescBuilder();
241             stats.fieldsFrom(groupDescStats);
242             groupDesc.setGroupDesc(stats.build());
243
244             //Update augmented data
245             groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
246
247             trans.putOperationalData(groupRef, groupBuilder.build());
248             this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
249         }
250
251         trans.commit();
252     }
253
254
255     public synchronized void updateGroupStats(List<GroupStats> list) {
256         final DataModificationTransaction trans = statisticsProvider.startChange();
257
258         for(GroupStats groupStats : list) {
259             GroupBuilder groupBuilder = new GroupBuilder();
260             GroupKey groupKey = new GroupKey(groupStats.getGroupId());
261             groupBuilder.setKey(groupKey);
262
263             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
264                                                                                         .augmentation(FlowCapableNode.class)
265                                                                                         .child(Group.class,groupKey).toInstance();
266
267             NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
268             GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
269             stats.fieldsFrom(groupStats);
270             groupStatisticsBuilder.setGroupStatistics(stats.build());
271
272             //Update augmented data
273             groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
274             trans.putOperationalData(groupRef, groupBuilder.build());
275
276             // FIXME: should we be tracking this data?
277         }
278
279         trans.commit();
280     }
281
282     public synchronized void updateMeterConfigStats(List<MeterConfigStats> list) {
283         final Long expiryTime = getExpiryTime();
284         final DataModificationTransaction trans = statisticsProvider.startChange();
285
286         for(MeterConfigStats meterConfigStats : list) {
287             MeterBuilder meterBuilder = new MeterBuilder();
288             MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
289             meterBuilder.setKey(meterKey);
290
291             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
292                                                                                         .augmentation(FlowCapableNode.class)
293                                                                                         .child(Meter.class,meterKey).toInstance();
294
295             NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
296             MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
297             stats.fieldsFrom(meterConfigStats);
298             meterConfig.setMeterConfigStats(stats.build());
299
300             //Update augmented data
301             meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
302
303             trans.putOperationalData(meterRef, meterBuilder.build());
304             this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
305         }
306
307         trans.commit();
308     }
309
310
311     public synchronized void updateMeterStats(List<MeterStats> list) {
312         final DataModificationTransaction trans = statisticsProvider.startChange();
313
314         for(MeterStats meterStats : list) {
315             MeterBuilder meterBuilder = new MeterBuilder();
316             MeterKey meterKey = new MeterKey(meterStats.getMeterId());
317             meterBuilder.setKey(meterKey);
318
319             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
320                                                                                         .augmentation(FlowCapableNode.class)
321                                                                                         .child(Meter.class,meterKey).toInstance();
322
323             NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
324             MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
325             stats.fieldsFrom(meterStats);
326             meterStatsBuilder.setMeterStatistics(stats.build());
327
328             //Update augmented data
329             meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
330             trans.putOperationalData(meterRef, meterBuilder.build());
331
332             // FIXME: should we be tracking this data?
333         }
334
335         trans.commit();
336     }
337
338     public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> list) {
339         final Long expiryTime = getExpiryTime();
340         final DataModificationTransaction trans = statisticsProvider.startChange();
341
342         for (QueueIdAndStatisticsMap swQueueStats : list) {
343
344             QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
345
346             FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
347
348             FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
349
350             queueStatisticsBuilder.fieldsFrom(swQueueStats);
351
352             queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
353
354             InstanceIdentifier<Queue> queueRef
355                     = InstanceIdentifier.builder(Nodes.class)
356                                         .child(Node.class, targetNodeKey)
357                                         .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
358                                         .augmentation(FlowCapableNodeConnector.class)
359                                         .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
360
361             QueueBuilder queueBuilder = new QueueBuilder();
362             FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
363             queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
364             queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
365
366             logger.debug("Augmenting queue statistics {} of queue {} to port {}",
367                                         qsd,
368                                         swQueueStats.getQueueId(),
369                                         swQueueStats.getNodeConnectorId());
370
371             trans.putOperationalData(queueRef, queueBuilder.build());
372             this.queuesStatsUpdate.put(queueEntry, expiryTime);
373         }
374
375         trans.commit();
376     }
377
378     public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
379         final DataModificationTransaction trans = statisticsProvider.startChange();
380
381         for (FlowTableAndStatisticsMap ftStats : list) {
382
383             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
384                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
385
386             FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
387
388             FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
389             statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
390             statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
391             statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
392
393             final FlowTableStatistics stats = statisticsBuilder.build();
394             statisticsDataBuilder.setFlowTableStatistics(stats);
395
396             logger.debug("Augment flow table statistics: {} for table {} on Node {}",
397                     stats,ftStats.getTableId(), targetNodeKey);
398
399             TableBuilder tableBuilder = new TableBuilder();
400             tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
401             tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
402             trans.putOperationalData(tableRef, tableBuilder.build());
403
404             // FIXME: should we be tracking this data?
405         }
406
407         trans.commit();
408     }
409
410     public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> list) {
411         final DataModificationTransaction trans = statisticsProvider.startChange();
412
413         for(NodeConnectorStatisticsAndPortNumberMap portStats : list) {
414
415             FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
416                                             = new FlowCapableNodeConnectorStatisticsBuilder();
417             statisticsBuilder.setBytes(portStats.getBytes());
418             statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
419             statisticsBuilder.setDuration(portStats.getDuration());
420             statisticsBuilder.setPackets(portStats.getPackets());
421             statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
422             statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
423             statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
424             statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
425             statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
426             statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
427             statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
428
429             //Augment data to the node-connector
430             FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
431                     new FlowCapableNodeConnectorStatisticsDataBuilder();
432
433             statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
434
435             InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class)
436                     .child(Node.class, targetNodeKey)
437                     .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
438
439             // FIXME: can we bypass this read?
440             NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
441             if(nodeConnector != null){
442                 final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
443                 logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
444                 NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
445                 nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
446                 trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
447             }
448
449             // FIXME: should we be tracking this data?
450         }
451
452         trans.commit();
453     }
454
455     public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) {
456         if (tableId != null) {
457             final DataModificationTransaction trans = statisticsProvider.startChange();
458
459
460             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
461                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
462
463             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
464             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
465
466             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
467
468             logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
469                     aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
470
471             TableBuilder tableBuilder = new TableBuilder();
472             tableBuilder.setKey(new TableKey(tableId));
473             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
474             trans.putOperationalData(tableRef, tableBuilder.build());
475
476             // FIXME: should we be tracking this data?
477             trans.commit();
478         }
479     }
480
481     public synchronized void updateGroupFeatures(GroupFeatures notification) {
482         final DataModificationTransaction trans = statisticsProvider.startChange();
483
484         final NodeBuilder nodeData = new NodeBuilder();
485         nodeData.setKey(targetNodeKey);
486
487         NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
488         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
489         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
490
491         //Update augmented data
492         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
493         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
494
495         // FIXME: should we be tracking this data?
496         trans.commit();
497     }
498
499     public synchronized void updateMeterFeatures(MeterFeatures features) {
500         final DataModificationTransaction trans = statisticsProvider.startChange();
501
502         final NodeBuilder nodeData = new NodeBuilder();
503         nodeData.setKey(targetNodeKey);
504
505         NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
506         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
507         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
508
509         //Update augmented data
510         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
511         trans.putOperationalData(targetNodeIdentifier, nodeData.build());
512
513         // FIXME: should we be tracking this data?
514         trans.commit();
515     }
516
517     public synchronized void updateFlowStats(FlowEntry flowEntry){
518         this.flowStatsUpdate.put(flowEntry, getExpiryTime());
519     }
520
521     private static Long getExpiryTime(){
522         final long now = System.nanoTime();
523         return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES);
524     }
525
526     public synchronized void cleanStaleStatistics(){
527         final DataModificationTransaction trans = this.statisticsProvider.startChange();
528         final long now = System.nanoTime();
529
530         //Clean stale statistics related to group
531         for (Iterator<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
532             Entry<GroupDescStats, Long> e = it.next();
533             if (now > e.getValue()) {
534                 cleanGroupStatsFromDataStore(trans, e.getKey());
535                 it.remove();
536             }
537         }
538
539         //Clean stale statistics related to meter
540         for (Iterator<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
541             Entry<MeterConfigStats, Long> e = it.next();
542             if (now > e.getValue()) {
543                 cleanMeterStatsFromDataStore(trans, e.getKey());
544                 it.remove();
545             }
546         }
547
548         //Clean stale statistics related to flow
549         for (Iterator<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
550             Entry<FlowEntry, Long> e = it.next();
551             if (now > e.getValue()) {
552                 cleanFlowStatsFromDataStore(trans, e.getKey());
553                 it.remove();
554             }
555         }
556
557         //Clean stale statistics related to queue
558         for (Iterator<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
559             Entry<QueueEntry, Long> e = it.next();
560             if (now > e.getValue()) {
561                 cleanQueueStatsFromDataStore(trans, e.getKey());
562                 it.remove();
563             }
564         }
565
566         trans.commit();
567     }
568
569     private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) {
570         InstanceIdentifier<?> queueRef
571                         = InstanceIdentifier.builder(Nodes.class)
572                                             .child(Node.class, this.targetNodeKey)
573                                             .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
574                                             .augmentation(FlowCapableNodeConnector.class)
575                                             .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
576                                             .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
577         trans.removeOperationalData(queueRef);
578     }
579
580     private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) {
581         InstanceIdentifier<?> flowRef
582                         = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
583                                             .augmentation(FlowCapableNode.class)
584                                             .child(Table.class, new TableKey(flowEntry.getTableId()))
585                                             .child(Flow.class,flowEntry.getFlow().getKey())
586                                             .augmentation(FlowStatisticsData.class).toInstance();
587         trans.removeOperationalData(flowRef);
588     }
589
590     private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) {
591         InstanceIdentifierBuilder<Meter> meterRef
592                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
593                                             .augmentation(FlowCapableNode.class)
594                                             .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
595
596         InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
597         trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
598
599         InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
600         trans.removeOperationalData(nodeMeterStatisticsAugmentation);
601     }
602
603     private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) {
604         InstanceIdentifierBuilder<Group> groupRef
605                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
606                                             .augmentation(FlowCapableNode.class)
607                                             .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
608
609         InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
610         trans.removeOperationalData(nodeGroupDescStatsAugmentation);
611
612         InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
613         trans.removeOperationalData(nodeGroupStatisticsAugmentation);
614     }
615
616 }