Remove unused parameters
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnOpDataSyncer.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  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.netvirt.vpnmanager;
9
10 import com.google.common.collect.ImmutableMap;
11 import com.google.common.util.concurrent.ThreadFactoryBuilder;
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.ThreadFactory;
22 import javax.inject.Singleton;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * Aims to provide a common synchronization point for all those classes that
28  * want to know when certain type of Operational data is ready for a given VPN,
29  * and those others that can notify that the Operational data is ready.
30  */
31 @Singleton
32 public class VpnOpDataSyncer {
33
34     static final Logger LOG = LoggerFactory.getLogger(VpnOpDataSyncer.class);
35
36     public enum VpnOpDataType {
37         vpnInstanceToId,
38         vpnOpData,
39     }
40
41     // Maps VpnOpDataType to a Map of VpnName to a list of tasks to be executed once the the Vpn is fully ready.
42     private final Map<VpnOpDataType, ConcurrentMap<String, List<Runnable>>> mapOfMaps =
43         ImmutableMap.<VpnOpDataType, ConcurrentMap<String, List<Runnable>>>builder()
44             .put(VpnOpDataType.vpnInstanceToId, new ConcurrentHashMap<>())
45             .put(VpnOpDataType.vpnOpData, new ConcurrentHashMap<>())
46             .build();
47
48
49     private static final ThreadFactory THREAD_FACTORY =
50         new ThreadFactoryBuilder().setNameFormat("NV-VpnMgr-%d").build();
51     private final ExecutorService executorService = Executors.newSingleThreadExecutor(THREAD_FACTORY);
52
53
54     public boolean waitForVpnDataReady(VpnOpDataType vpnOpDataType, String vpnName, long maxWaitMillis,
55                                        int maxAttempts) {
56         int attempts = 0;
57         boolean isDataReady = false;
58         do {
59             attempts++;
60             isDataReady = waitForVpnDataReady(vpnOpDataType, vpnName, maxWaitMillis);
61         }
62         while (!isDataReady && attempts < maxAttempts);
63
64         return isDataReady;
65     }
66
67     // "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
68     // see comments below.
69     @SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
70     public boolean waitForVpnDataReady(VpnOpDataType dataType, String vpnName, long maxWaitMillis) {
71         //TODO(vivek) This waiting business to be removed in carbon
72         boolean dataReady = false;
73         ConcurrentMap<String, List<Runnable>> listenerMap = mapOfMaps.get(dataType);
74         Runnable notifyTask = new VpnNotifyTask();
75         try {
76             List<Runnable> notifyList = listenerMap.computeIfAbsent(vpnName,
77                 k -> Collections.synchronizedList(new ArrayList<>()));
78
79             synchronized (notifyTask) {
80                 // Per FB's "Unconditional wait" violation, the code should really verify that the condition it intends
81                 // to wait for is not already satisfied before calling wait. However the VpnNotifyTask is published
82                 // here while holding the lock on it so this path will hit the wait before notify can be invoked.
83                 notifyList.add(notifyTask);
84
85                 long t0 = System.nanoTime();
86                 try {
87                     notifyTask.wait(maxWaitMillis);
88                     long elapsedTimeNs = System.nanoTime() - t0;
89
90                     if (elapsedTimeNs < maxWaitMillis * 1000000) {
91                         // Thread woken up before timeout
92                         LOG.debug("Its been reported that VPN {} is now ready", vpnName);
93                         dataReady = true;
94                     } else {
95                         // Timeout
96                         LOG.debug("Vpn {} OpData not ready after {}ms", vpnName, maxWaitMillis);
97                         dataReady = false;
98                     }
99                 } catch (InterruptedException e) {
100                     dataReady = true;
101                 }
102             }
103         } finally {
104             List<Runnable> notifyTaskList = listenerMap.get(vpnName);
105             if (notifyTaskList != null) {
106                 synchronized (notifyTaskList) {
107                     notifyTaskList.remove(notifyTask);
108                     if (notifyTaskList.isEmpty()) {
109                         listenerMap.remove(vpnName);
110                     }
111                 }
112             }
113         }
114         return dataReady;
115     }
116
117     public void notifyVpnOpDataReady(VpnOpDataType dataType, String vpnName) {
118         LOG.debug("Reporting that vpn {} is ready", vpnName);
119         ConcurrentMap<String, List<Runnable>> listenerMap = mapOfMaps.get(dataType);
120         List<Runnable> notifyTaskList = listenerMap.remove(vpnName);
121         if (notifyTaskList == null) {
122             LOG.trace(" No notify tasks found for vpnName {}", vpnName);
123             return;
124         }
125
126         Runnable[] notifyTasks;
127         synchronized (notifyTaskList) {
128             notifyTasks = notifyTaskList.toArray(new Runnable[notifyTaskList.size()]);
129             notifyTaskList.clear();
130         }
131
132         for (Runnable notifyTask : notifyTasks) {
133             executorService.execute(notifyTask);
134         }
135     }
136 }