All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer Maven / Gradle / Ivy

There is a newer version: 0.11.4
Show newest version
/*
 * 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