Merge "Optimize statistics cleanup"
[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.MeterKey;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
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.NodeKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
46
47 import com.google.common.base.Preconditions;
48
49 /**
50  * Main responsibility of this class to clean up all the stale statistics data
51  * associated to Flow,Meter,Group,Queue.
52  * @author avishnoi@in.ibm.com
53  *
54  */
55 public class NodeStatisticsAger {
56     private static final int NUMBER_OF_WAIT_CYCLES = 2;
57
58     private final Map<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
59     private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
60     private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
61     private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
62     private final StatisticsProvider statisticsProvider;
63     private final NodeKey targetNodeKey;
64
65     public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){
66         this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider);
67         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
68     }
69
70     public class FlowEntry {
71         private final Short tableId;
72         private final Flow flow;
73
74         public FlowEntry(Short tableId, Flow flow){
75             this.tableId = tableId;
76             this.flow = flow;
77         }
78
79         public Short getTableId() {
80             return tableId;
81         }
82
83         public Flow getFlow() {
84             return flow;
85         }
86
87         @Override
88         public int hashCode() {
89             final int prime = 31;
90             int result = 1;
91             result = prime * result + getOuterType().hashCode();
92             result = prime * result + ((flow == null) ? 0 : flow.hashCode());
93             result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
94             return result;
95         }
96
97         @Override
98         public boolean equals(Object obj) {
99             if (this == obj)
100                 return true;
101             if (obj == null)
102                 return false;
103             if (getClass() != obj.getClass())
104                 return false;
105             FlowEntry other = (FlowEntry) obj;
106             if (!getOuterType().equals(other.getOuterType()))
107                 return false;
108             if (flow == null) {
109                 if (other.flow != null)
110                     return false;
111             } else if (!flow.equals(other.flow))
112                 return false;
113             if (tableId == null) {
114                 if (other.tableId != null)
115                     return false;
116             } else if (!tableId.equals(other.tableId))
117                 return false;
118             return true;
119         }
120
121         private NodeStatisticsAger getOuterType() {
122             return NodeStatisticsAger.this;
123         }
124     }
125
126     public class QueueEntry{
127         private final NodeConnectorId nodeConnectorId;
128         private final QueueId queueId;
129         public QueueEntry(NodeConnectorId ncId, QueueId queueId){
130             this.nodeConnectorId = ncId;
131             this.queueId = queueId;
132         }
133         public NodeConnectorId getNodeConnectorId() {
134             return nodeConnectorId;
135         }
136         public QueueId getQueueId() {
137             return queueId;
138         }
139         @Override
140         public int hashCode() {
141             final int prime = 31;
142             int result = 1;
143             result = prime * result + getOuterType().hashCode();
144             result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
145             result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
146             return result;
147         }
148         @Override
149         public boolean equals(Object obj) {
150             if (this == obj) {
151                 return true;
152             }
153             if (obj == null) {
154                 return false;
155             }
156             if (!(obj instanceof QueueEntry)) {
157                 return false;
158             }
159             QueueEntry other = (QueueEntry) obj;
160             if (!getOuterType().equals(other.getOuterType())) {
161                 return false;
162             }
163             if (nodeConnectorId == null) {
164                 if (other.nodeConnectorId != null) {
165                     return false;
166                 }
167             } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
168                 return false;
169             }
170             if (queueId == null) {
171                 if (other.queueId != null) {
172                     return false;
173                 }
174             } else if (!queueId.equals(other.queueId)) {
175                 return false;
176             }
177             return true;
178         }
179         private NodeStatisticsAger getOuterType() {
180             return NodeStatisticsAger.this;
181         }
182     }
183
184     public NodeKey getTargetNodeKey() {
185         return targetNodeKey;
186     }
187
188     public synchronized void updateGroupDescStats(List<GroupDescStats> list){
189         Long expiryTime = getExpiryTime();
190         for(GroupDescStats groupDescStats : list)
191             this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
192     }
193
194     public synchronized void updateMeterConfigStats(List<MeterConfigStats> list){
195         Long expiryTime = getExpiryTime();
196         for(MeterConfigStats meterConfigStats: list)
197             this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
198     }
199
200     public synchronized void updateFlowStats(FlowEntry flowEntry){
201         this.flowStatsUpdate.put(flowEntry, getExpiryTime());
202     }
203     public synchronized void updateQueueStats(QueueEntry queueEntry){
204         this.queuesStatsUpdate.put(queueEntry, getExpiryTime());
205     }
206
207     private static Long getExpiryTime(){
208         final long now = System.nanoTime();
209         return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES);
210     }
211
212     public synchronized void cleanStaleStatistics(){
213         final DataModificationTransaction trans = this.statisticsProvider.startChange();
214         final long now = System.nanoTime();
215
216         //Clean stale statistics related to group
217         for (Iterator<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
218             Entry<GroupDescStats, Long> e = it.next();
219             if (now > e.getValue()) {
220                 cleanGroupStatsFromDataStore(trans, e.getKey());
221                 it.remove();
222             }
223         }
224
225         //Clean stale statistics related to meter
226         for (Iterator<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
227             Entry<MeterConfigStats, Long> e = it.next();
228             if (now > e.getValue()) {
229                 cleanMeterStatsFromDataStore(trans, e.getKey());
230                 it.remove();
231             }
232         }
233
234         //Clean stale statistics related to flow
235         for (Iterator<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
236             Entry<FlowEntry, Long> e = it.next();
237             if (now > e.getValue()) {
238                 cleanFlowStatsFromDataStore(trans, e.getKey());
239                 it.remove();
240             }
241         }
242
243         //Clean stale statistics related to queue
244         for (Iterator<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
245             Entry<QueueEntry, Long> e = it.next();
246             if (now > e.getValue()) {
247                 cleanQueueStatsFromDataStore(trans, e.getKey());
248                 it.remove();
249             }
250         }
251
252         trans.commit();
253     }
254
255     private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) {
256         InstanceIdentifier<?> queueRef
257                         = InstanceIdentifier.builder(Nodes.class)
258                                             .child(Node.class, this.targetNodeKey)
259                                             .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
260                                             .augmentation(FlowCapableNodeConnector.class)
261                                             .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
262                                             .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
263         trans.removeOperationalData(queueRef);
264     }
265
266     private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) {
267         InstanceIdentifier<?> flowRef
268                         = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
269                                             .augmentation(FlowCapableNode.class)
270                                             .child(Table.class, new TableKey(flowEntry.getTableId()))
271                                             .child(Flow.class,flowEntry.getFlow().getKey())
272                                             .augmentation(FlowStatisticsData.class).toInstance();
273         trans.removeOperationalData(flowRef);
274     }
275
276     private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) {
277         InstanceIdentifierBuilder<Meter> meterRef
278                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
279                                             .augmentation(FlowCapableNode.class)
280                                             .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
281
282         InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
283         trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
284
285         InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
286         trans.removeOperationalData(nodeMeterStatisticsAugmentation);
287     }
288
289     private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) {
290         InstanceIdentifierBuilder<Group> groupRef
291                         = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
292                                             .augmentation(FlowCapableNode.class)
293                                             .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
294
295         InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
296         trans.removeOperationalData(nodeGroupDescStatsAugmentation);
297
298         InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
299         trans.removeOperationalData(nodeGroupStatisticsAugmentation);
300     }
301 }