org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer Maven / Gradle / Ivy
/*
* Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.netvirt.vpnmanager;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Aims to provide a common synchronization point for all those classes that
* want to know when certain type of Operational data is ready for a given VPN,
* and those others that can notify that the Operational data is ready.
*/
@Singleton
public class VpnOpDataSyncer {
private static final Logger LOG = LoggerFactory.getLogger(VpnOpDataSyncer.class);
public enum VpnOpDataType {
vpnInstanceToId,
vpnOpData,
}
// Maps VpnOpDataType to a Map of VpnName to a list of tasks to be executed once the the Vpn is fully ready.
private final Map>> mapOfMaps =
ImmutableMap.>>builder()
.put(VpnOpDataType.vpnInstanceToId, new ConcurrentHashMap<>())
.put(VpnOpDataType.vpnOpData, new ConcurrentHashMap<>())
.build();
private static final ThreadFactory THREAD_FACTORY =
new ThreadFactoryBuilder().setNameFormat("NV-VpnMgr-%d").build();
private final ExecutorService executorService = Executors.newSingleThreadExecutor(THREAD_FACTORY);
public boolean waitForVpnDataReady(VpnOpDataType vpnOpDataType, String vpnName, long maxWaitMillis,
int maxAttempts) {
int attempts = 0;
boolean isDataReady = false;
do {
attempts++;
isDataReady = waitForVpnDataReady(vpnOpDataType, vpnName, maxWaitMillis);
}
while (!isDataReady && attempts < maxAttempts);
return isDataReady;
}
// "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
// see comments below.
@SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
public boolean waitForVpnDataReady(VpnOpDataType dataType, String vpnName, long maxWaitMillis) {
//TODO(vivek) This waiting business to be removed in carbon
boolean dataReady = false;
ConcurrentMap> listenerMap = mapOfMaps.get(dataType);
Runnable notifyTask = new VpnNotifyTask();
try {
List notifyList = listenerMap.computeIfAbsent(vpnName,
k -> Collections.synchronizedList(new ArrayList<>()));
synchronized (notifyTask) {
// Per FB's "Unconditional wait" violation, the code should really verify that the condition it intends
// to wait for is not already satisfied before calling wait. However the VpnNotifyTask is published
// here while holding the lock on it so this path will hit the wait before notify can be invoked.
notifyList.add(notifyTask);
long t0 = System.nanoTime();
try {
notifyTask.wait(maxWaitMillis);
long elapsedTimeNs = System.nanoTime() - t0;
if (elapsedTimeNs < maxWaitMillis * 1000000) {
// Thread woken up before timeout
LOG.debug("Its been reported that VPN {} is now ready", vpnName);
dataReady = true;
} else {
// Timeout
LOG.debug("Vpn {} OpData not ready after {}ms", vpnName, maxWaitMillis);
dataReady = false;
}
} catch (InterruptedException e) {
dataReady = true;
}
}
} finally {
List notifyTaskList = listenerMap.get(vpnName);
if (notifyTaskList != null) {
synchronized (notifyTaskList) {
notifyTaskList.remove(notifyTask);
if (notifyTaskList.isEmpty()) {
listenerMap.remove(vpnName);
}
}
}
}
return dataReady;
}
public void notifyVpnOpDataReady(VpnOpDataType dataType, String vpnName) {
LOG.debug("Reporting that vpn {} is ready", vpnName);
ConcurrentMap> listenerMap = mapOfMaps.get(dataType);
List notifyTaskList = listenerMap.remove(vpnName);
if (notifyTaskList == null) {
LOG.trace(" No notify tasks found for vpnName {}", vpnName);
return;
}
Runnable[] notifyTasks;
synchronized (notifyTaskList) {
notifyTasks = notifyTaskList.toArray(new Runnable[notifyTaskList.size()]);
notifyTaskList.clear();
}
for (Runnable notifyTask : notifyTasks) {
executorService.execute(notifyTask);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy