Properly check for FlowRef before touching caches 86/94586/6
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 10 Jan 2021 12:26:34 +0000 (13:26 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 10 Jan 2021 19:08:04 +0000 (20:08 +0100)
FlowRef is not necessarily present, hence we need to properly
isolate code that requires it.

This ends up being a larger-scale refactor, as there was a ton
of duplicate code. At the end of the day, this debugging facility's
footprint is reasonably reduced.

JIRA: OPNFLWPLUG-1106
Change-Id: I402cc302ab09e22bda7f731f7da4431f576c8bbb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
applications/southbound-cli/src/main/java/org/opendaylight/openflowplugin/applications/southboundcli/cli/GetFlowGroupCacheProvider.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupCache.java [deleted file]
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupCacheManager.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupInfo.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/cache/FlowGroupCacheManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/SalFlowServiceImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/SalGroupServiceImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/SalFlowServiceImplTest.java

index fbc8d7f0e9e577b9f04542e1019b493a6ad81870..0207bbe30b0c6608b44ff9f07e6ba81ee31f8cd2 100644 (file)
@@ -9,16 +9,17 @@ package org.opendaylight.openflowplugin.applications.southboundcli.cli;
 
 import static org.opendaylight.openflowplugin.applications.frm.util.FrmUtil.OPENFLOW_PREFIX;
 
-import java.util.ArrayList;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Collection;
 import java.util.Formatter;
-import java.util.List;
 import java.util.Map;
-import java.util.Queue;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
 import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupCache;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupCacheManager;
+import org.opendaylight.openflowplugin.api.openflow.FlowGroupInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 
 @Command(scope = "openflow", name = "getflownodecache", description = "Print all flow/group cache")
 public class GetFlowGroupCacheProvider extends OsgiCommandSupport {
@@ -32,65 +33,72 @@ public class GetFlowGroupCacheProvider extends OsgiCommandSupport {
         this.flowGroupCacheManager = flowGroupCacheManager;
     }
 
-    @SuppressWarnings("checkstyle:RegexpSinglelineJava")
     @Override
-    protected Object doExecute() throws Exception {
-        String nodeId = OPENFLOW_PREFIX + dpnId;
-        List<String> result = new ArrayList<>();
-
+    @SuppressWarnings("checkstyle:RegexpSinglelineJava")
+    protected Object doExecute() {
         if (dpnId == null) {
-            Map<String, Queue<FlowGroupCache>> flowGroupCacheListForAllNodes = flowGroupCacheManager
-                    .getAllNodesFlowGroupCache();
-            if (!flowGroupCacheListForAllNodes.isEmpty()) {
-                StringBuilder stringBuilder = new StringBuilder();
-                Formatter formatter = new Formatter(stringBuilder);
-                result.add(getAllLocalNodesHeaderOutput());
-                result.add(getLineSeparator());
-                for (Map.Entry<String, Queue<FlowGroupCache>> cacheEntry : flowGroupCacheListForAllNodes.entrySet()) {
-                    String[] temp = cacheEntry.getKey().split(":");
-                    String node = temp[1];
-                    Queue<FlowGroupCache> flowGroupCacheList = cacheEntry.getValue();
-                    synchronized (flowGroupCacheList) {
-                        for (FlowGroupCache cache : flowGroupCacheList) {
-                            result.add(formatter.format("%-15s %1s %-10s %1s %-8s %1s %-21s %1s %-60s",
-                                    node, "", cache.getDescription(), "", cache.getStatus(), "",
-                                    cache.getTime(), "", cache.getId()).toString());
-                            stringBuilder.setLength(0);
-                        }
-                    }
-                }
-                formatter.close();
-                result.stream().forEach(p -> System.out.println(p));
-            } else {
-                session.getConsole().println("No flow/group is programmed yet");
-            }
-        } else {
-            if (!flowGroupCacheManager.getAllNodesFlowGroupCache().containsKey(nodeId)) {
-                session.getConsole().println("No node available for this NodeID");
-                return null;
-            }
-            Queue<FlowGroupCache> flowGroupCacheList = flowGroupCacheManager.getAllNodesFlowGroupCache()
-                    .get(nodeId);
-            if (!flowGroupCacheList.isEmpty()) {
-                StringBuilder stringBuilder = new StringBuilder();
-                Formatter formatter = new Formatter(stringBuilder);
-                result.add(String.format("Number of flows and groups in cache for node %s : %d", nodeId,
-                        flowGroupCacheList.size()));
-                result.add(getLocalNodeHeaderOutput());
-                result.add(getLineSeparator());
-                for (FlowGroupCache cache : flowGroupCacheList) {
-                    result.add(formatter.format("%-10s %1s %-8s %1s %-23s %1s %-60s",
-                            cache.getDescription(), "", cache.getStatus(), "",
-                            cache.getTime(), "", cache.getId()).toString());
-                    stringBuilder.setLength(0);
+            printAllNodes();
+            return null;
+        }
+
+        final String nodeId = OPENFLOW_PREFIX + dpnId;
+        Collection<FlowGroupInfo> flowGroupCacheList = flowGroupCacheManager.getFlowGroupCache(new NodeId(nodeId));
+        if (flowGroupCacheList == null) {
+            session.getConsole().println("No node available for this NodeID");
+            return null;
+        }
+        if (flowGroupCacheList.isEmpty()) {
+            session.getConsole().println("No flow/group is programmed yet for the the node " + nodeId);
+            return null;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        Formatter fmt = new Formatter(sb);
+        System.out.println(String.format("Number of flows and groups in cache for node %s : %d", nodeId,
+            flowGroupCacheList.size()));
+        System.out.println(getLocalNodeHeaderOutput());
+        System.out.println(getLineSeparator());
+
+        for (FlowGroupInfo cache : flowGroupCacheList) {
+            System.out.println(fmt.format("%-10s %1s %-8s %1s %-23s %1s %-60s", cache.getDescription(), "",
+                cache.getStatus(), "", getTime(cache), "", cache.getId()).toString());
+            sb.setLength(0);
+        }
+        fmt.close();
+        return null;
+    }
+
+    private static LocalDateTime getTime(final FlowGroupInfo info) {
+        return LocalDateTime.ofInstant(info.getInstantUTC(), ZoneOffset.UTC);
+    }
+
+    @SuppressWarnings("checkstyle:RegexpSinglelineJava")
+    private void printAllNodes() {
+        final Map<NodeId, Collection<FlowGroupInfo>> allGroupInfos = flowGroupCacheManager.getAllNodesFlowGroupCache();
+        if (allGroupInfos.isEmpty()) {
+            session.getConsole().println("No flow/group is programmed yet");
+            return;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        Formatter fmt = new Formatter(sb);
+        System.out.println(getAllLocalNodesHeaderOutput());
+        System.out.println(getLineSeparator());
+        for (Map.Entry<NodeId, Collection<FlowGroupInfo>> cacheEntry : allGroupInfos.entrySet()) {
+            // FIXME: just seek/substring
+            String[] temp = cacheEntry.getKey().getValue().split(":");
+            String node = temp[1];
+            Collection<FlowGroupInfo> flowGroupCacheList = cacheEntry.getValue();
+            synchronized (flowGroupCacheList) {
+                for (FlowGroupInfo cache : flowGroupCacheList) {
+                    System.out.println(fmt.format("%-15s %1s %-10s %1s %-8s %1s %-21s %1s %-60s", node, "",
+                        cache.getDescription(), "", cache.getStatus(), "", getTime(cache), "",
+                        cache.getId()).toString());
+                    sb.setLength(0);
                 }
-                formatter.close();
-                result.stream().forEach(p -> System.out.println(p));
-            } else {
-                session.getConsole().println("No flow/group is programmed yet for the the node " + nodeId);
             }
         }
-        return null;
+        fmt.close();
     }
 
     private static String getLocalNodeHeaderOutput() {
diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupCache.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupCache.java
deleted file mode 100644 (file)
index 63f22bb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2020 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.openflowplugin.api.openflow;
-
-import java.time.LocalDateTime;
-
-public class FlowGroupCache {
-    private final String id;
-    private final String description;
-    private final FlowGroupStatus status;
-    private final LocalDateTime time;
-
-    public FlowGroupCache(String id, String description, FlowGroupStatus status,
-                          LocalDateTime time) {
-        this.id = id;
-        this.description = description;
-        this.status = status;
-        this.time = time;
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public FlowGroupStatus getStatus() {
-        return status;
-    }
-
-    public LocalDateTime getTime() {
-        return time;
-    }
-}
index b206aa4a78262c13e7bf37e2f4cc7507a47d380b..51ee56d7e69101c7aaa50a1516537b78e802c471 100644 (file)
@@ -7,12 +7,28 @@
  */
 package org.opendaylight.openflowplugin.api.openflow;
 
+import java.util.Collection;
 import java.util.Map;
-import java.util.Queue;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.common.Uint8;
 
 public interface FlowGroupCacheManager {
 
     Map<String, ReconciliationState> getReconciliationStates();
 
-    Map<String, Queue<FlowGroupCache>> getAllNodesFlowGroupCache();
+    // FIXME: this quite unrelated to getReconciliationStates() to the point
+    Map<NodeId, Collection<FlowGroupInfo>> getAllNodesFlowGroupCache();
+
+    @Nullable Collection<FlowGroupInfo> getFlowGroupCache(@NonNull NodeId nodeId);
+
+    // FIXME: these two methods should live in a separate interface
+    void appendFlow(@NonNull NodeId nodeId, @NonNull FlowId id, Uint8 tableId, @NonNull FlowGroupStatus status);
+
+    void appendGroup(@NonNull NodeId nodeId, @NonNull GroupId id, @NonNull GroupTypes type,
+        @NonNull FlowGroupStatus status);
 }
diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupInfo.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/FlowGroupInfo.java
new file mode 100644 (file)
index 0000000..151a1ce
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 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.openflowplugin.api.openflow;
+
+import static java.util.Objects.requireNonNull;
+
+import java.time.Instant;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.Uint8;
+
+@NonNullByDefault
+public abstract class FlowGroupInfo implements Immutable {
+    private static final class Flow extends FlowGroupInfo {
+        private final Uint8 tableId;
+        private final FlowId id;
+
+        Flow(final FlowGroupStatus status, final FlowId id, final Uint8 tableId) {
+            super(status);
+            this.id = requireNonNull(id);
+            this.tableId = requireNonNull(tableId);
+        }
+
+        @Override
+        public String getId() {
+            return id.getValue();
+        }
+
+        @Override
+        public String getDescription() {
+            return tableId.toString();
+        }
+    }
+
+    private static final class Group extends FlowGroupInfo {
+        private final GroupTypes type;
+        private final GroupId id;
+
+        Group(final FlowGroupStatus status, final GroupId id, final GroupTypes type) {
+            super(status);
+            this.id = requireNonNull(id);
+            this.type = requireNonNull(type);
+        }
+
+        @Override
+        public String getId() {
+            // FIXME: GroupId.toString() is not pretty, can we do something else?
+            return id.toString();
+        }
+
+        @Override
+        public String getDescription() {
+            return type.getName();
+        }
+    }
+
+    private final Instant time = Instant.now();
+    private final FlowGroupStatus status;
+
+    private FlowGroupInfo(final FlowGroupStatus status) {
+        this.status = requireNonNull(status);
+    }
+
+    public static FlowGroupInfo ofFlow(final FlowId id, final Uint8 tableId, final FlowGroupStatus status) {
+        return new Flow(status, id, tableId);
+    }
+
+    public static FlowGroupInfo ofGroup(final GroupId id, final GroupTypes type, final FlowGroupStatus status) {
+        return new Group(status, id, type);
+    }
+
+    public abstract String getId();
+
+    public abstract String getDescription();
+
+    public final FlowGroupStatus getStatus() {
+        return status;
+    }
+
+    public final Instant getInstantUTC() {
+        return time;
+    }
+}
index 4f6b6a28d1c4a985199e2f991e5837b0a43103d0..0f92c006e97d3e52cd31a91283a3779763a2d487 100644 (file)
@@ -7,29 +7,70 @@
  */
 package org.opendaylight.openflowplugin.impl.services.cache;
 
+import com.google.common.collect.EvictingQueue;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Queues;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
 import javax.inject.Singleton;
 import org.apache.aries.blueprint.annotation.service.Service;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupCache;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupCacheManager;
+import org.opendaylight.openflowplugin.api.openflow.FlowGroupInfo;
+import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.ReconciliationState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.common.Uint8;
 
 @Singleton
 @Service(classes = FlowGroupCacheManager.class)
 public class FlowGroupCacheManagerImpl implements FlowGroupCacheManager {
+    // FIXME: make this configurable and expose a different implementation at least for OSGi when this is switched off
+    private static final int FLOWGROUP_CACHE_SIZE = 10000;
 
-    private Map<String, ReconciliationState> reconciliationStates = new ConcurrentHashMap<>();
-    private Map<String, Queue<FlowGroupCache>> allNodesFlowGroupCache = new ConcurrentHashMap<>();
+    private final Map<String, ReconciliationState> reconciliationStates = new ConcurrentHashMap<>();
+    private final Map<NodeId, Queue<FlowGroupInfo>> flowGroups = new ConcurrentHashMap<>();
 
     @Override
-    public Map<String, Queue<FlowGroupCache>> getAllNodesFlowGroupCache() {
-        return allNodesFlowGroupCache;
+    public Map<String, ReconciliationState> getReconciliationStates() {
+        return reconciliationStates;
     }
 
     @Override
-    public Map<String, ReconciliationState> getReconciliationStates() {
-        return reconciliationStates;
+    public Map<NodeId, Collection<FlowGroupInfo>> getAllNodesFlowGroupCache() {
+        return Collections.unmodifiableMap(Maps.transformValues(flowGroups, Collections::unmodifiableCollection));
+    }
+
+    @Override
+    public Collection<FlowGroupInfo> getFlowGroupCache(final NodeId nodeId) {
+        final Collection<FlowGroupInfo> result = flowGroups.get(nodeId);
+        return result == null ? List.of() : Collections.unmodifiableCollection(result);
+    }
+
+    @Override
+    public void appendFlow(final NodeId nodeId, final FlowId id, final Uint8 tableId, final FlowGroupStatus status) {
+        flowGroup(nodeId).add(FlowGroupInfo.ofFlow(id, tableId, status));
+    }
+
+    @Override
+    public void appendGroup(final NodeId nodeId, final GroupId id, final GroupTypes type,
+            final FlowGroupStatus status) {
+        flowGroup(nodeId).add(FlowGroupInfo.ofGroup(id, type, status));
+    }
+
+    // FIXME: we really want to split out the 'nodeId' lookup and provide an internal interface for the plugin to
+    //        contribute directly to the queue.
+    private @NonNull Queue<FlowGroupInfo> flowGroup(final NodeId nodeId) {
+        return flowGroups.computeIfAbsent(nodeId,
+            // FIXME: synchronized queue relies on locking -- and most of the time all we access it from the same(-ish)
+            //        context. We should be able to do better.
+            key -> Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE)));
     }
 }
\ No newline at end of file
index a9f4c04e6439e66a8d246ec33ff9d5c571eca8f3..e843e131c146cfa352edf7c316b7ced152a92763 100644 (file)
@@ -7,19 +7,14 @@
  */
 package org.opendaylight.openflowplugin.impl.services.sal;
 
-import com.google.common.collect.EvictingQueue;
-import com.google.common.collect.Queues;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
-import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Queue;
 import org.opendaylight.openflowplugin.api.OFConstants;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupCache;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupCacheManager;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
@@ -48,6 +43,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.Upda
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
 import org.opendaylight.yangtools.yang.common.RpcError;
@@ -59,6 +55,8 @@ import org.slf4j.LoggerFactory;
 
 public class SalFlowServiceImpl implements SalFlowService {
     private static final Logger LOG = LoggerFactory.getLogger(SalFlowServiceImpl.class);
+    private static final Uint8 OFPTT_ALL = Uint8.MAX_VALUE;
+
     private final MultiLayerFlowService<UpdateFlowOutput> flowUpdate;
     private final MultiLayerFlowService<AddFlowOutput> flowAdd;
     private final MultiLayerFlowService<RemoveFlowOutput> flowRemove;
@@ -66,10 +64,7 @@ public class SalFlowServiceImpl implements SalFlowService {
     private final SingleLayerFlowService<UpdateFlowOutput> flowUpdateMessage;
     private final SingleLayerFlowService<RemoveFlowOutput> flowRemoveMessage;
     private final DeviceContext deviceContext;
-    private static final Uint8 OFPTT_ALL = Uint8.MAX_VALUE;
     private final FlowGroupCacheManager provider;
-    public static final int FLOWGROUP_CACHE_SIZE = 10000;
-
 
     public SalFlowServiceImpl(final RequestContextStack requestContextStack,
                               final DeviceContext deviceContext,
@@ -133,7 +128,7 @@ public class SalFlowServiceImpl implements SalFlowService {
     public ListenableFuture<RpcResult<UpdateFlowOutput>> updateFlow(final UpdateFlowInput input) {
         final UpdatedFlow updated = input.getUpdatedFlow();
         final OriginalFlow original = input.getOriginalFlow();
-        String nodeId =  PathUtil.extractNodeId(input.getNode()).getValue();
+        final NodeId nodeId = PathUtil.extractNodeId(input.getNode());
         final List<FlowModInputBuilder> allFlowMods = new ArrayList<>();
         final List<FlowModInputBuilder> ofFlowModInputs;
 
@@ -150,7 +145,7 @@ public class SalFlowServiceImpl implements SalFlowService {
                 Futures.addCallback(listListenableFuture, new FutureCallback<List<RpcResult<UpdateFlowOutput>>>() {
                     @Override
                     public void onSuccess(final List<RpcResult<UpdateFlowOutput>> results) {
-                        final ArrayList<RpcError> errors = new ArrayList();
+                        final ArrayList<RpcError> errors = new ArrayList<>();
                         for (RpcResult<UpdateFlowOutput> flowModResult : results) {
                             if (flowModResult == null) {
                                 errors.add(RpcResultBuilder.newError(
@@ -221,35 +216,30 @@ public class SalFlowServiceImpl implements SalFlowService {
 
         @Override
         public void onSuccess(final RpcResult<AddFlowOutput> rpcResult) {
-            if (rpcResult.isSuccessful()) {
-                final FlowDescriptor flowDescriptor;
-                final FlowId flowId = input.getFlowRef().getValue().firstKeyOf(Flow.class).getId();
-                FlowGroupCache cache = new FlowGroupCache(flowId.getValue(), input.getTableId().toString(),
-                        FlowGroupStatus.ADDED, LocalDateTime.now());
-                if (provider.getAllNodesFlowGroupCache().containsKey(nodeId.getValue())) {
-                    provider.getAllNodesFlowGroupCache().get(nodeId.getValue()).add(cache);
-                } else {
-                    Queue<FlowGroupCache> flowGroupCacheList =
-                            Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                    flowGroupCacheList.add(cache);
-                    provider.getAllNodesFlowGroupCache().put(nodeId.getValue(), flowGroupCacheList);
-                }
-                if (input.getFlowRef() != null) {
-                    flowDescriptor = FlowDescriptorFactory.create(input.getTableId(), flowId);
-                    deviceContext.getDeviceFlowRegistry().storeDescriptor(flowRegistryKey, flowDescriptor);
-                } else {
-                    deviceContext.getDeviceFlowRegistry().store(flowRegistryKey);
-                    flowDescriptor = deviceContext.getDeviceFlowRegistry().retrieveDescriptor(flowRegistryKey);
-                }
-
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug("Flow add with id={} finished without error", flowDescriptor.getFlowId().getValue());
-                }
-            } else {
+            if (!rpcResult.isSuccessful()) {
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Flow add failed for flow={}, errors={}", input,
                             ErrorUtil.errorsToString(rpcResult.getErrors()));
                 }
+                return;
+            }
+
+            final FlowDescriptor flowDescriptor;
+            final FlowRef flowRef = input.getFlowRef();
+            if (flowRef != null) {
+                final Uint8 tableId = input.getTableId();
+                final FlowId flowId = flowRef.getValue().firstKeyOf(Flow.class).getId();
+                provider.appendFlow(nodeId, flowId, tableId, FlowGroupStatus.ADDED);
+
+                flowDescriptor = FlowDescriptorFactory.create(tableId, flowId);
+                deviceContext.getDeviceFlowRegistry().storeDescriptor(flowRegistryKey, flowDescriptor);
+            } else {
+                deviceContext.getDeviceFlowRegistry().store(flowRegistryKey);
+                flowDescriptor = deviceContext.getDeviceFlowRegistry().retrieveDescriptor(flowRegistryKey);
+            }
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Flow add with id={} finished without error", flowDescriptor.getFlowId().getValue());
             }
         }
 
@@ -278,17 +268,11 @@ public class SalFlowServiceImpl implements SalFlowService {
                     FlowRegistryKey flowRegistryKey =
                             FlowRegistryKeyFactory.create(deviceContext.getDeviceInfo().getVersion(), input);
                     deviceContext.getDeviceFlowRegistry().addMark(flowRegistryKey);
-                    final FlowId flowId = input.getFlowRef().getValue().firstKeyOf(Flow.class).getId();
-                    FlowGroupCache cache = new FlowGroupCache(flowId.getValue(),
-                            input.getTableId().toString(), FlowGroupStatus.REMOVED,
-                            LocalDateTime.now());
-                    if (provider.getAllNodesFlowGroupCache().containsKey(nodeId.getValue())) {
-                        provider.getAllNodesFlowGroupCache().get(nodeId.getValue()).add(cache);
-                    } else {
-                        Queue<FlowGroupCache> flowGroupCacheList =
-                                Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                        flowGroupCacheList.add(cache);
-                        provider.getAllNodesFlowGroupCache().put(nodeId.getValue(), flowGroupCacheList);
+
+                    final FlowRef flowRef = input.getFlowRef();
+                    if (flowRef != null) {
+                        final FlowId flowId = flowRef.getValue().firstKeyOf(Flow.class).getId();
+                        provider.appendFlow(nodeId, flowId, input.getTableId(), FlowGroupStatus.REMOVED);
                     }
                 } else {
                     deviceContext.getDeviceFlowRegistry().clearFlowRegistry();
@@ -309,9 +293,9 @@ public class SalFlowServiceImpl implements SalFlowService {
 
     private final class UpdateFlowCallback implements FutureCallback<RpcResult<UpdateFlowOutput>> {
         private final UpdateFlowInput input;
-        private final String nodeId;
+        private final NodeId nodeId;
 
-        private UpdateFlowCallback(UpdateFlowInput input,  String nodeId) {
+        private UpdateFlowCallback(final UpdateFlowInput input, final NodeId nodeId) {
             this.input = input;
             this.nodeId = nodeId;
         }
@@ -319,7 +303,6 @@ public class SalFlowServiceImpl implements SalFlowService {
         @Override
         public void onSuccess(final RpcResult<UpdateFlowOutput> updateFlowOutputRpcResult) {
             final DeviceFlowRegistry deviceFlowRegistry = deviceContext.getDeviceFlowRegistry();
-            final FlowId flowId = input.getFlowRef().getValue().firstKeyOf(Flow.class).getId();
             final UpdatedFlow updated = input.getUpdatedFlow();
             final OriginalFlow original = input.getOriginalFlow();
             final FlowRegistryKey origFlowRegistryKey =
@@ -330,29 +313,18 @@ public class SalFlowServiceImpl implements SalFlowService {
 
             final boolean isUpdate = origFlowDescriptor != null;
             final FlowDescriptor updatedFlowDescriptor;
-            FlowGroupCache cache = new FlowGroupCache(flowId.getValue(), updated.getTableId().toString(),
-                    FlowGroupStatus.MODIFIED,
-                    LocalDateTime.now());
-            if (provider.getAllNodesFlowGroupCache().containsKey(nodeId)) {
-                provider.getAllNodesFlowGroupCache().get(nodeId).add(cache);
-            } else {
-                Queue<FlowGroupCache> flowGroupCacheList =
-                        Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                flowGroupCacheList.add(cache);
-                provider.getAllNodesFlowGroupCache().put(nodeId, flowGroupCacheList);
-            }
-
-            if (input.getFlowRef() != null) {
-                updatedFlowDescriptor =
-                        FlowDescriptorFactory.create(updated.getTableId(),
-                                                     input.getFlowRef().getValue().firstKeyOf(Flow.class).getId());
+            final FlowRef flowRef = input.getFlowRef();
+            if (flowRef != null) {
+                final Uint8 tableId = updated.getTableId();
+                final FlowId flowId = flowRef.getValue().firstKeyOf(Flow.class).getId();
+                provider.appendFlow(nodeId, flowId, tableId, FlowGroupStatus.MODIFIED);
+
+                updatedFlowDescriptor = FlowDescriptorFactory.create(tableId, flowId);
+            } else if (isUpdate) {
+                updatedFlowDescriptor = origFlowDescriptor;
             } else {
-                if (isUpdate) {
-                    updatedFlowDescriptor = origFlowDescriptor;
-                } else {
-                    deviceFlowRegistry.store(updatedFlowRegistryKey);
-                    updatedFlowDescriptor = deviceFlowRegistry.retrieveDescriptor(updatedFlowRegistryKey);
-                }
+                deviceFlowRegistry.store(updatedFlowRegistryKey);
+                updatedFlowDescriptor = deviceFlowRegistry.retrieveDescriptor(updatedFlowRegistryKey);
             }
 
             if (isUpdate) {
index df8380b7e20e8987e8b80c3b54113aa875b036c4..a363d19bca2c2b8d5012f414a7eaac3e58cb252f 100755 (executable)
@@ -7,15 +7,10 @@
  */
 package org.opendaylight.openflowplugin.impl.services.sal;
 
-import com.google.common.collect.EvictingQueue;
-import com.google.common.collect.Queues;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
-import java.time.LocalDateTime;
-import java.util.Queue;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupCache;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupCacheManager;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
@@ -32,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.Rem
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -84,23 +80,13 @@ public class SalGroupServiceImpl implements SalGroupService {
             addGroupMessage.canUseSingleLayerSerialization()
             ? addGroupMessage.handleServiceCall(input)
             : addGroup.handleServiceCall(input);
-        String nodeId =  PathUtil.extractNodeId(input.getNode()).getValue();
+        NodeId nodeId = PathUtil.extractNodeId(input.getNode());
         Futures.addCallback(resultFuture, new FutureCallback<RpcResult<AddGroupOutput>>() {
             @Override
-            public void onSuccess(RpcResult<AddGroupOutput> result) {
+            public void onSuccess(final RpcResult<AddGroupOutput> result) {
                 if (result.isSuccessful()) {
                     LOG.debug("adding group successful {}", input.getGroupId());
-                    FlowGroupCache cache = new FlowGroupCache(input.getGroupId().toString(),
-                            input.getGroupType().getName(), FlowGroupStatus.ADDED,
-                            LocalDateTime.now());
-                    if (provider.getAllNodesFlowGroupCache().containsKey(nodeId)) {
-                        provider.getAllNodesFlowGroupCache().get(nodeId).add(cache);
-                    } else {
-                        Queue<FlowGroupCache> flowGroupCacheList =
-                                Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                        flowGroupCacheList.add(cache);
-                        provider.getAllNodesFlowGroupCache().put(nodeId, flowGroupCacheList);
-                    }
+                    provider.appendGroup(nodeId, input.getGroupId(), input.getGroupType(), FlowGroupStatus.ADDED);
                 } else {
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("Group add with id={} failed, errors={}", input.getGroupId().getValue(),
@@ -110,7 +96,7 @@ public class SalGroupServiceImpl implements SalGroupService {
             }
 
             @Override
-            public void onFailure(Throwable throwable) {
+            public void onFailure(final Throwable throwable) {
                 LOG.warn("Service call for adding group={} failed",
                           input.getGroupId().getValue(),
                           throwable);
@@ -129,21 +115,11 @@ public class SalGroupServiceImpl implements SalGroupService {
 
         Futures.addCallback(resultFuture, new FutureCallback<RpcResult<UpdateGroupOutput>>() {
             @Override
-            public void onSuccess(RpcResult<UpdateGroupOutput> result) {
+            public void onSuccess(final RpcResult<UpdateGroupOutput> result) {
                 if (result.isSuccessful()) {
-                    NodeId nodeId = PathUtil.extractNodeId(input.getNode());
-                    FlowGroupCache cache = new FlowGroupCache(
-                            input.getUpdatedGroup().getGroupId().getValue().toString(),
-                            input.getUpdatedGroup().getGroupType().getName(), FlowGroupStatus.MODIFIED,
-                            LocalDateTime.now());
-                    if (provider.getAllNodesFlowGroupCache().containsKey(nodeId.getValue())) {
-                        provider.getAllNodesFlowGroupCache().get(nodeId.getValue()).add(cache);
-                    } else {
-                        Queue<FlowGroupCache> flowGroupCacheList =
-                                Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                        flowGroupCacheList.add(cache);
-                        provider.getAllNodesFlowGroupCache().put(nodeId.getValue(), flowGroupCacheList);
-                    }
+                    UpdatedGroup updatedGroup = input.getUpdatedGroup();
+                    provider.appendGroup(PathUtil.extractNodeId(input.getNode()),
+                        updatedGroup.getGroupId(), updatedGroup.getGroupType(), FlowGroupStatus.MODIFIED);
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("Group update with original id={} finished without error",
                             input.getOriginalGroup().getGroupId().getValue());
@@ -156,7 +132,7 @@ public class SalGroupServiceImpl implements SalGroupService {
             }
 
             @Override
-            public void onFailure(Throwable throwable) {
+            public void onFailure(final Throwable throwable) {
                 LOG.warn("Service call for updating group={} failed",
                         input.getOriginalGroup().getGroupId(), throwable);
             }
@@ -173,22 +149,12 @@ public class SalGroupServiceImpl implements SalGroupService {
 
         Futures.addCallback(resultFuture, new FutureCallback<RpcResult<RemoveGroupOutput>>() {
             @Override
-            public void onSuccess(RpcResult<RemoveGroupOutput> result) {
+            public void onSuccess(final RpcResult<RemoveGroupOutput> result) {
                 if (result.isSuccessful()) {
                     if (LOG.isDebugEnabled()) {
-                        NodeId nodeId = PathUtil.extractNodeId(input.getNode());
                         LOG.debug("Group remove with id={} finished without error", input.getGroupId().getValue());
-                        FlowGroupCache cache = new FlowGroupCache(input.getGroupId().getValue().toString(),
-                                input.getGroupType().getName(), FlowGroupStatus.REMOVED,
-                                LocalDateTime.now());
-                        if (provider.getAllNodesFlowGroupCache().containsKey(nodeId.getValue())) {
-                            provider.getAllNodesFlowGroupCache().get(nodeId.getValue()).add(cache);
-                        } else {
-                            Queue<FlowGroupCache> flowGroupCacheList =
-                                    Queues.synchronizedQueue(EvictingQueue.create(FLOWGROUP_CACHE_SIZE));
-                            flowGroupCacheList.add(cache);
-                            provider.getAllNodesFlowGroupCache().put(nodeId.getValue(), flowGroupCacheList);
-                        }
+                        provider.appendGroup(PathUtil.extractNodeId(input.getNode()), input.getGroupId(),
+                            input.getGroupType(), FlowGroupStatus.REMOVED);
                     }
                 } else {
                     LOG.warn("Group remove with id={} failed, errors={}", input.getGroupId().getValue(),
@@ -198,7 +164,7 @@ public class SalGroupServiceImpl implements SalGroupService {
             }
 
             @Override
-            public void onFailure(Throwable throwable) {
+            public void onFailure(final Throwable throwable) {
                 LOG.warn("Service call for removing group={} failed",
                         input.getGroupId().getValue(), throwable);
             }
index f982788c6a1138a7b223358984aa38eb637265f2..6bcfb5e7faf2c1ff9a4c441df4c12656f14f0861 100644 (file)
@@ -11,11 +11,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.common.util.concurrent.Futures;
-import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Queue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import junit.framework.TestCase;
@@ -28,8 +23,6 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
 import org.opendaylight.openflowplugin.api.OFConstants;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupCache;
-import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
@@ -78,7 +71,7 @@ import org.opendaylight.yangtools.yang.common.Uint32;
 import org.opendaylight.yangtools.yang.common.Uint64;
 import org.opendaylight.yangtools.yang.common.Uint8;
 
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class SalFlowServiceImplTest extends TestCase {
 
     private static final Uint64 DUMMY_DATAPATH_ID = Uint64.valueOf(444);
@@ -93,25 +86,6 @@ public class SalFlowServiceImplTest extends TestCase {
             = NODE_II.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(DUMMY_TABLE_ID));
 
     private final NodeRef noderef = new NodeRef(NODE_II);
-    private static final String KEY = "0";
-    private static FlowGroupCache flowcache =
-            new FlowGroupCache("0","mock class", FlowGroupStatus.ADDED, LocalDateTime.MAX);
-
-    private static Queue<FlowGroupCache> caches() {
-        Queue<FlowGroupCache> cache = new LinkedList<>();
-        cache.add(flowcache);
-        return cache;
-    }
-
-    private static final Queue<FlowGroupCache> CACHE = caches();
-
-    private static Map<String, Queue<FlowGroupCache>> createMap() {
-        Map<String,Queue<FlowGroupCache>> myMap = new HashMap<>();
-        myMap.put(KEY, CACHE);
-        return myMap;
-    }
-
-    private static final Map<String, Queue<FlowGroupCache>> MYMAP = createMap();
 
     @Mock
     private RequestContextStack mockedRequestContextStack;
@@ -159,7 +133,6 @@ public class SalFlowServiceImplTest extends TestCase {
         when(mockedDeviceInfo.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID);
 
         when(mockedDeviceContext.getDeviceInfo()).thenReturn(mockedDeviceInfo);
-        when(flowGroupCacheManager.getAllNodesFlowGroupCache()).thenReturn(MYMAP);
     }
 
     private SalFlowServiceImpl mockSalFlowService(final short version) {