Merge "BUG 1839 - HTTP delete of non existing data"
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / impl / StatPermCollectorImpl.java
1 package org.opendaylight.controller.md.statistics.manager.impl;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Map.Entry;
8 import java.util.concurrent.ExecutorService;
9 import java.util.concurrent.Executors;
10 import java.util.concurrent.ThreadFactory;
11
12 import org.opendaylight.controller.md.statistics.manager.StatPermCollector;
13 import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
17 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import com.google.common.base.Preconditions;
22 import com.google.common.util.concurrent.ThreadFactoryBuilder;
23
24 /**
25  * statistics-manager
26  * org.opendaylight.controller.md.statistics.manager.impl
27  *
28  * StatPermCollectorImpl
29  * Thread base statistic collector. Class holds internal map for all registered
30  * (means connected) nodes with List of Switch capabilities;
31  * Statistics collecting process get cross whole Network Device by device
32  * and statistic by statistic (follow Switch capabilities to prevent unnecessary
33  * ask) Next statistic start collecting by notification or by timeout.
34  *
35  * @author @author avishnoi@in.ibm.com <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
36  *
37  */
38 public class StatPermCollectorImpl implements StatPermCollector {
39
40     private final static Logger LOG = LoggerFactory.getLogger(StatPermCollectorImpl.class);
41
42     private final static long STAT_COLLECT_TIME_OUT = 30000L;
43
44     private final ExecutorService statNetCollectorServ;
45     private final StatisticsManager manager;
46
47     private final int maxNodeForCollector;
48     private final long minReqNetInterval;
49     private final String name;
50
51     private final Object statCollectorLock = new Object();
52     private final Object statNodeHolderLock = new Object();
53
54     private Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNodeHolder =
55             Collections.<InstanceIdentifier<Node>, StatNodeInfoHolder> emptyMap();
56
57     private volatile boolean wakeMe = false;
58     private volatile boolean finishing = false;
59
60     public StatPermCollectorImpl(final StatisticsManager manager, final long minReqNetInterv, final int nr,
61             final int maxNodeForCollectors) {
62         this.manager = Preconditions.checkNotNull(manager, "StatisticsManager can not be null!");
63         name = "odl-stat-collector-" + nr;
64         minReqNetInterval = minReqNetInterv;
65         final ThreadFactory threadFact = new ThreadFactoryBuilder()
66             .setNameFormat(name + "-thread-%d").build();
67         statNetCollectorServ = Executors.newSingleThreadExecutor(threadFact);
68         maxNodeForCollector = maxNodeForCollectors;
69         LOG.trace("StatCollector {} start successfull!", name);
70     }
71
72     /**
73      * finish collecting statistics
74      */
75     @Override
76     public void close() {
77         statNodeHolder = Collections.<InstanceIdentifier<Node>, StatNodeInfoHolder> emptyMap();
78         finishing = true;
79         collectNextStatistics();
80         statNetCollectorServ.shutdown();
81     }
82
83     @Override
84     public boolean isProvidedFlowNodeActive(
85             final InstanceIdentifier<Node> flowNode) {
86         return statNodeHolder.containsKey(flowNode);
87     }
88
89     @Override
90     public boolean connectedNodeRegistration(final InstanceIdentifier<Node> ident,
91             final List<StatCapabTypes> statTypes, final Short nrOfSwitchTables) {
92         if (ident.isWildcarded()) {
93             LOG.warn("FlowCapableNode IstanceIdentifier {} registration can not be wildcarded!", ident);
94         } else {
95             if ( ! statNodeHolder.containsKey(ident)) {
96                 synchronized (statNodeHolderLock) {
97                     final boolean startStatCollecting = statNodeHolder.size() == 0;
98                     if ( ! statNodeHolder.containsKey(ident)) {
99                         if (statNodeHolder.size() >= maxNodeForCollector) {
100                             return false;
101                         }
102                         final Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNode =
103                                 new HashMap<>(statNodeHolder);
104                         final NodeRef nodeRef = new NodeRef(ident);
105                         final StatNodeInfoHolder nodeInfoHolder = new StatNodeInfoHolder(nodeRef,
106                                 statTypes, nrOfSwitchTables);
107                         statNode.put(ident, nodeInfoHolder);
108                         statNodeHolder = Collections.unmodifiableMap(statNode);
109                     }
110                     if (startStatCollecting) {
111                         finishing = false;
112                         statNetCollectorServ.execute(this);
113                     }
114                 }
115             }
116         }
117         return true;
118     }
119
120     @Override
121     public boolean disconnectedNodeUnregistration(final InstanceIdentifier<Node> ident) {
122         if (ident.isWildcarded()) {
123             LOG.warn("FlowCapableNode IstanceIdentifier {} unregistration can not be wildcarded!", ident);
124         } else {
125             if (statNodeHolder.containsKey(ident)) {
126                 synchronized (statNodeHolderLock) {
127                     if (statNodeHolder.containsKey(ident)) {
128                         final Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNode =
129                                 new HashMap<>(statNodeHolder);
130                         statNode.remove(ident);
131                         statNodeHolder = Collections.unmodifiableMap(statNode);
132                     }
133                     if (statNodeHolder.isEmpty()) {
134                         finishing = true;
135                         collectNextStatistics();
136                         statNetCollectorServ.shutdown();
137                     }
138                     return true;
139                 }
140             }
141         }
142         return false;
143     }
144
145     @Override
146     public void collectNextStatistics() {
147         if (wakeMe) {
148             synchronized (statCollectorLock) {
149                 if (wakeMe) {
150                     LOG.trace("STAT-COLLECTOR is notified to conntinue");
151                     statCollectorLock.notify();
152                 }
153             }
154         }
155     }
156
157     @Override
158     public void run() {
159         try {
160             Thread.sleep(5000);
161         }
162         catch (final InterruptedException e1) {
163             // NOOP
164         }
165         LOG.debug("StatCollector {} Start collecting!", name);
166          /* Neverending cyle - wait for finishing */
167          while ( ! finishing) {
168             boolean collecting = false;
169             final long startTime = System.currentTimeMillis();
170
171             if ( ! statNodeHolder.isEmpty()) {
172                 collecting = true;
173                 collectStatCrossNetwork();
174                 collecting = false;
175             }
176
177             if ( ! collecting) {
178                 final long statFinalTime = System.currentTimeMillis() - startTime;
179                 LOG.debug("STAT-MANAGER {}: last all NET statistics collection cost {} ms", name, statFinalTime);
180                 if (statFinalTime < minReqNetInterval) {
181                     LOG.trace("statCollector is about to make a collecting sleep");
182                     synchronized (statCollectorLock) {
183                         wakeMe = true;
184                         try {
185                             final long waitTime = minReqNetInterval - statFinalTime;
186                             statCollectorLock.wait(waitTime);
187                             LOG.trace("STAT-MANAGER : statCollector {} is waking up from a collecting sleep for {} ms", name, waitTime);
188                         } catch (final InterruptedException e) {
189                             LOG.warn("statCollector has been interrupted during collecting sleep", e);
190                         } finally {
191                             wakeMe = false;
192                         }
193                     }
194                 }
195             }
196         }
197     }
198
199     private void waitingForNotification() {
200         synchronized (statCollectorLock) {
201             wakeMe = true;
202             try {
203                 statCollectorLock.wait(STAT_COLLECT_TIME_OUT);
204                 LOG.trace("statCollector is waking up from a wait stat Response sleep");
205             } catch (final InterruptedException e) {
206                 LOG.warn("statCollector has been interrupted waiting stat Response sleep", e);
207             } finally {
208                 wakeMe = false;
209             }
210         }
211     }
212
213
214     private void collectStatCrossNetwork() {
215         for (final Entry<InstanceIdentifier<Node>, StatNodeInfoHolder> nodeEntity : statNodeHolder.entrySet()) {
216             final List<StatCapabTypes> listNeededStat = nodeEntity.getValue().getStatMarkers();
217             final NodeRef actualNodeRef = nodeEntity.getValue().getNodeRef();
218             final Short maxTables = nodeEntity.getValue().getMaxTables();
219             for (final StatCapabTypes statMarker : listNeededStat) {
220                 if ( ! isProvidedFlowNodeActive(nodeEntity.getKey())) {
221                     break;
222                 }
223                 switch (statMarker) {
224                 case PORT_STATS:
225                     LOG.trace("STAT-MANAGER-collecting PORT-STATS for NodeRef {}", actualNodeRef);
226                     manager.getRpcMsgManager().getAllPortsStat(actualNodeRef);
227                     waitingForNotification();
228                     break;
229                 case QUEUE_STATS:
230                     LOG.trace("STAT-MANAGER-collecting QUEUE-STATS for NodeRef {}", actualNodeRef);
231                     manager.getRpcMsgManager().getAllQueueStat(actualNodeRef);
232                     waitingForNotification();
233                     break;
234                 case TABLE_STATS:
235                     LOG.trace("STAT-MANAGER-collecting TABLE-STATS for NodeRef {}", actualNodeRef);
236                     manager.getRpcMsgManager().getAllTablesStat(actualNodeRef);
237                     waitingForNotification();
238                     break;
239                 case GROUP_STATS:
240                     LOG.trace("STAT-MANAGER-collecting GROUP-STATS for NodeRef {}", actualNodeRef);
241                     manager.getRpcMsgManager().getGroupFeaturesStat(actualNodeRef);
242                     waitingForNotification();
243                     manager.getRpcMsgManager().getAllGroupsConfStats(actualNodeRef);
244                     waitingForNotification();
245                     manager.getRpcMsgManager().getAllGroupsStat(actualNodeRef);
246                     waitingForNotification();
247                     break;
248                 case METER_STATS:
249                     LOG.trace("STAT-MANAGER-collecting METER-STATS for NodeRef {}", actualNodeRef);
250                     manager.getRpcMsgManager().getMeterFeaturesStat(actualNodeRef);
251                     waitingForNotification();
252                     manager.getRpcMsgManager().getAllMeterConfigStat(actualNodeRef);
253                     waitingForNotification();
254                     manager.getRpcMsgManager().getAllMetersStat(actualNodeRef);
255                     waitingForNotification();
256                     break;
257                 case FLOW_STATS:
258                     LOG.trace("STAT-MANAGER-collecting FLOW-STATS-ALL_FLOWS for NodeRef {}", actualNodeRef);
259                     manager.getRpcMsgManager().getAllFlowsStat(actualNodeRef);
260                     waitingForNotification();
261                     LOG.trace("STAT-MANAGER-collecting FLOW-AGGREGATE-STATS for NodeRef {}", actualNodeRef);
262                     for (short i = 0; i < maxTables; i++) {
263                         final TableId tableId = new TableId(i);
264                         manager.getRpcMsgManager().getAggregateFlowStat(actualNodeRef, tableId);
265                     }
266                     break;
267                 default:
268                     /* Exception for programmers in implementation cycle */
269                     throw new IllegalStateException("Not implemented ASK for " + statMarker);
270                 }
271             }
272         }
273     }
274
275     private class StatNodeInfoHolder {
276         private final NodeRef nodeRef;
277         private final List<StatCapabTypes> statMarkers;
278         private final Short maxTables;
279
280         public StatNodeInfoHolder(final NodeRef nodeRef,
281                 final List<StatCapabTypes> statMarkers, final Short maxTables) {
282             this.nodeRef = nodeRef;
283             this.maxTables = maxTables;
284             this.statMarkers = statMarkers;
285         }
286
287         public final NodeRef getNodeRef() {
288             return nodeRef;
289         }
290
291         public final List<StatCapabTypes> getStatMarkers() {
292             return statMarkers;
293         }
294
295         public final Short getMaxTables() {
296             return maxTables;
297         }
298     }
299
300     @Override
301     public boolean hasActiveNodes() {
302         return ( ! statNodeHolder.isEmpty());
303     }
304 }
305