Adding l2gw related cache changes 41/83341/7
authormanojna v <manojna.vijayakrishna@ericsson.com>
Wed, 31 Jul 2019 10:26:00 +0000 (15:56 +0530)
committerChetan Arakere Gowdru <chetan.arakere@altencalsoftlabs.com>
Fri, 23 Aug 2019 12:32:34 +0000 (12:32 +0000)
Performance improvement to reduce DS reads by making
use of caches efficiently.

Change-Id: I4cdcfad6019c078fc406e41d94010e299dd234d9
Signed-off-by: manojna v <manojna.vijayakrishna@ericsson.com>
cache/impl/src/main/java/org/opendaylight/netvirt/cache/impl/l2gw/L2GatewayCacheImpl.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanGroupCache.java [new file with mode: 0644]
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/ElanMacTableCache.java [new file with mode: 0644]
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepConfigNodeCache.java [new file with mode: 0644]
neutronvpn/api/src/main/java/org/opendaylight/netvirt/neutronvpn/api/l2gw/L2GatewayCache.java

index 2384631eeaf4a6ddf4eb0b49573bddaf2f933800..27cdf98d8da18d5b7c49c32463246b6a8bc84ede 100644 (file)
@@ -9,12 +9,17 @@ package org.opendaylight.netvirt.cache.impl.l2gw;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import javax.inject.Singleton;
 import org.apache.aries.blueprint.annotation.service.Service;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
 
 /**
  * Implementation of L2GatewayCache.
@@ -25,15 +30,25 @@ import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 @Service(classes = L2GatewayCache.class)
 public class L2GatewayCacheImpl implements L2GatewayCache {
     private final ConcurrentMap<String, L2GatewayDevice> cache = new ConcurrentHashMap<>();
+    private final ConcurrentMap<String, L2GatewayDevice> cacheByNodeId = new ConcurrentHashMap<>();
 
     @Override
     public L2GatewayDevice addOrGet(String deviceName) {
         return cache.computeIfAbsent(deviceName, key -> new L2GatewayDevice(deviceName));
     }
 
+    @Override
+    public void add(String deviceName, L2GatewayDevice l2GatewayDevice) {
+        cache.put(deviceName, l2GatewayDevice);
+    }
+
     @Override
     public L2GatewayDevice remove(String deviceName) {
-        return deviceName != null ? cache.remove(deviceName) : null;
+        L2GatewayDevice l2GatewayDevice = deviceName != null ? cache.remove(deviceName) : null;
+        if (l2GatewayDevice != null && l2GatewayDevice.getHwvtepNodeId() != null) {
+            cacheByNodeId.remove(l2GatewayDevice.getHwvtepNodeId());
+        }
+        return l2GatewayDevice;
     }
 
     @Override
@@ -41,8 +56,56 @@ public class L2GatewayCacheImpl implements L2GatewayCache {
         return deviceName != null ? cache.get(deviceName) : null;
     }
 
+    @Override
+    public L2GatewayDevice getByNodeId(String nodeId) {
+        return nodeId != null ? (L2GatewayDevice) cacheByNodeId.get(nodeId) : null;
+    }
+
     @Override
     public Collection<L2GatewayDevice> getAll() {
         return Collections.unmodifiableCollection(cache.values());
     }
-}
+
+    @Override
+    public L2GatewayDevice updateL2GatewayCache(String deviceName, Uuid l2gwUuid) {
+        L2GatewayDevice l2GwDevice = get(deviceName);
+        if (l2GwDevice == null) {
+            l2GwDevice = new L2GatewayDevice(deviceName);
+            l2GwDevice.addL2GatewayId(l2gwUuid);
+        } else {
+            l2GwDevice.addL2GatewayId(l2gwUuid);
+        }
+
+        add(deviceName, l2GwDevice);
+        return l2GwDevice;
+    }
+
+    @Override
+    public L2GatewayDevice updateL2GatewayCache(String deviceName, String hwvtepNodeId, List<TunnelIps> tunnelIps) {
+        L2GatewayDevice l2GwDevice = get(deviceName);
+        if (l2GwDevice == null) {
+            l2GwDevice = new L2GatewayDevice(deviceName);
+        }
+
+        l2GwDevice.setConnected(true);
+        l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
+        if (tunnelIps != null && !tunnelIps.isEmpty()) {
+            Iterator var4 = tunnelIps.iterator();
+
+            while (var4.hasNext()) {
+                TunnelIps tunnelIp = (TunnelIps)var4.next();
+                IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
+                l2GwDevice.addTunnelIp(tunnelIpAddr);
+            }
+        }
+
+        add(deviceName, l2GwDevice);
+        cacheByNodeId.put(hwvtepNodeId, l2GwDevice);
+        return l2GwDevice;
+    }
+
+    @Override
+    public ConcurrentMap<String, L2GatewayDevice> getCache() {
+        return cache;
+    }
+}
\ No newline at end of file
diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanGroupCache.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanGroupCache.java
new file mode 100644 (file)
index 0000000..061d802
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019 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.elan.internal;
+
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.netvirt.elan.utils.Scheduler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ElanGroupCache extends AsyncClusteredDataTreeChangeListenerBase<Group, ElanGroupCache> {
+    private static final Logger LOG = LoggerFactory.getLogger(ElanGroupCache.class);
+    private final DataBroker dataBroker;
+    private final Scheduler scheduler;
+    private final Map<InstanceIdentifier<Group>, Group> groupsById = new ConcurrentHashMap<>();
+    private final Map<InstanceIdentifier<Group>, Collection<Runnable>> waitingJobs = new ConcurrentHashMap<>();
+    private volatile boolean initialized = false;
+
+    @Inject
+    public ElanGroupCache(final DataBroker dataBroker, final Scheduler scheduler) {
+        super(Group.class, ElanGroupCache.class);
+        this.dataBroker = dataBroker;
+        this.scheduler = scheduler;
+    }
+
+    public synchronized void init() {
+        if (!initialized) {
+            initialized = true;
+            this.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<Group> getWildCardPath() {
+        return InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class)
+                .child(Group.class).build();
+    }
+
+    public synchronized void addJobToWaitList(InstanceIdentifier<Group> key,
+                                              Runnable job) {
+        if (groupsById.containsKey(key)) {
+            job.run();
+        } else {
+            waitingJobs.putIfAbsent(key, new ArrayList<>());
+            waitingJobs.get(key).add(job);
+        }
+    }
+
+    @Override
+    protected ElanGroupCache getDataTreeChangeListener() {
+        return ElanGroupCache.this;
+    }
+
+    @Override
+    protected synchronized void remove(InstanceIdentifier<Group> key, Group deleted) {
+        groupsById.remove(key);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Group> key, Group old, Group updated) {
+        add(key, updated);
+    }
+
+    @Override
+    protected synchronized void add(InstanceIdentifier<Group> key, Group added) {
+        if (groupsById.containsKey(key)) {
+            groupsById.put(key, added);
+            return;
+        }
+        scheduler.getScheduledExecutorService().schedule(() -> {
+            groupsById.put(key, added);
+            Collection<Runnable> jobs = waitingJobs.remove(key);
+            if (jobs == null) {
+                return;
+            }
+            for (Runnable job : jobs) {
+                job.run();
+            }
+        }, ElanInterfaceManager.WAIT_TIME_FOR_SYNC_INSTALL, TimeUnit.MILLISECONDS);
+    }
+
+    public Optional<Group> getGroup(InstanceIdentifier<Group> key) throws ReadFailedException {
+        if (groupsById.containsKey(key)) {
+            return Optional.of(groupsById.get(key));
+        }
+        ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+        Optional<Group> optional = transaction.read(LogicalDatastoreType.CONFIGURATION, key).checkedGet();
+        transaction.close();
+        return optional;
+    }
+}
index d0ec7557a63934b3b1b8e348c7dc4292c03d9fd6..f3e2e969534d83ffb27be87eed01bbb7d35f9574 100644 (file)
@@ -148,7 +148,7 @@ import org.slf4j.LoggerFactory;
 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
         implements RecoverableListener {
     private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
-    private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
+    public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
     private static final boolean SH_FLAG_SET = true;
     private static final boolean SH_FLAG_UNSET = false;
 
diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/ElanMacTableCache.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/ElanMacTableCache.java
new file mode 100644 (file)
index 0000000..0df603c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 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.elan.l2gw.listeners;
+
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ElanMacTableCache extends AsyncClusteredDataTreeChangeListenerBase<MacTable, ElanMacTableCache> {
+    private static final Logger LOG = LoggerFactory.getLogger(ElanMacTableCache.class);
+    private final DataBroker dataBroker;
+    private final ConcurrentHashMap<String, MacTable> macsByElan = new ConcurrentHashMap<>();
+
+    @Inject
+    public ElanMacTableCache(final DataBroker dataBroker) {
+        super(MacTable.class, ElanMacTableCache.class);
+        this.dataBroker = dataBroker;
+    }
+
+    @PostConstruct
+    public void init() {
+        this.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+    }
+
+    @Override
+    protected InstanceIdentifier<MacTable> getWildCardPath() {
+        return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class).build();
+    }
+
+    @Override
+    protected ElanMacTableCache getDataTreeChangeListener() {
+        return ElanMacTableCache.this;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<MacTable> key, MacTable mac) {
+        macsByElan.remove(mac.getElanInstanceName());
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<MacTable> key, MacTable old, MacTable mac) {
+        macsByElan.put(mac.getElanInstanceName(), mac);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<MacTable> key, MacTable mac) {
+        macsByElan.put(mac.getElanInstanceName(), mac);
+    }
+
+    public MacTable getByElanName(String name) {
+        return macsByElan.get(name);
+    }
+}
\ No newline at end of file
diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepConfigNodeCache.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/listeners/HwvtepConfigNodeCache.java
new file mode 100644 (file)
index 0000000..401dee8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 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.elan.l2gw.listeners;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@Singleton
+public class HwvtepConfigNodeCache extends AsyncClusteredDataTreeChangeListenerBase<Node, HwvtepConfigNodeCache> {
+    private final DataBroker dataBroker;
+    private final Map<InstanceIdentifier<Node>, Node> cache = new ConcurrentHashMap<>();
+    private final Map<InstanceIdentifier<Node>, List<Runnable>> waitList = new ConcurrentHashMap<>();
+
+    @Inject
+    public HwvtepConfigNodeCache(final DataBroker dataBroker) {
+        super(Node.class, HwvtepConfigNodeCache.class);
+        this.dataBroker = dataBroker;
+    }
+
+    @PostConstruct
+    public void init() {
+        this.registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+    }
+
+    @Override
+    protected InstanceIdentifier<Node> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class);
+    }
+
+    @Override
+    protected HwvtepConfigNodeCache getDataTreeChangeListener() {
+        return HwvtepConfigNodeCache.this;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Node> key, Node deleted) {
+        cache.remove(key);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Node> key, Node old, Node added) {
+        cache.put(key, added);
+    }
+
+    @Override
+    protected synchronized void add(InstanceIdentifier<Node> key, Node added) {
+        cache.put(key, added);
+        if (waitList.containsKey(key)) {
+            waitList.remove(key).stream().forEach(runnable -> runnable.run());
+        }
+    }
+
+    public Node getConfigNode(InstanceIdentifier<Node> key) {
+        return cache.get(key);
+    }
+
+    public synchronized void runAfterNodeAvailable(InstanceIdentifier<Node> key, Runnable runnable) {
+        if (cache.containsKey(key)) {
+            runnable.run();
+        } else {
+            waitList.putIfAbsent(key, new ArrayList<>());
+            waitList.get(key).add(runnable);
+        }
+    }
+}
\ No newline at end of file
index 8f96fc70264ca376cadcf6b79ca955b32245734f..e2a588eb9decd8cff341dd33446c1ca36d777c83 100644 (file)
@@ -8,19 +8,39 @@
 package org.opendaylight.netvirt.neutronvpn.api.l2gw;
 
 import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+
+
 public interface L2GatewayCache {
     @NonNull
     L2GatewayDevice addOrGet(@NonNull String deviceName);
 
+    void add(@NonNull String deviceName, L2GatewayDevice l2GatewayDevice);
+
     @Nullable
     L2GatewayDevice remove(String deviceName);
 
     @Nullable
     L2GatewayDevice get(String deviceName);
 
+    @Nullable
+    L2GatewayDevice getByNodeId(String nodeId);
+
     @NonNull
     Collection<L2GatewayDevice> getAll();
+
+    @Nullable
+    L2GatewayDevice updateL2GatewayCache(String psName, Uuid l2gwUuid);
+
+    @Nullable
+    L2GatewayDevice updateL2GatewayCache(String psName, String hwvtepNodeId, List<TunnelIps> tunnelIps);
+
+    @NonNull
+    ConcurrentMap<String, L2GatewayDevice> getCache();
 }