Bug 6745 Improve compression queue locking and handle InterruptedException
[openflowplugin.git] / applications / forwardingrules-sync / src / main / java / org / opendaylight / openflowplugin / applications / frsync / impl / SimplifiedConfigListener.java
index 94265eccfc737c3c4c3248429039e538c146bfa9..d9f9a361e363981e7f8a9e02763403b0570ca263 100644 (file)
@@ -8,8 +8,10 @@
 
 package org.opendaylight.openflowplugin.applications.frsync.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collection;
-
+import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -17,55 +19,51 @@ import org.opendaylight.openflowplugin.applications.frsync.SyncReactor;
 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao;
 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao;
 import org.opendaylight.openflowplugin.applications.frsync.util.PathUtil;
+import org.opendaylight.openflowplugin.applications.frsync.util.SyncupEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
- * Listens to config changes and delegates add/remove/update/barrier to {@link SyncReactor}.
+ * Listens to config changes and delegates sync entry to {@link SyncReactor}.
  */
 public class SimplifiedConfigListener extends AbstractFrmSyncListener<FlowCapableNode> {
+
     private static final Logger LOG = LoggerFactory.getLogger(SimplifiedConfigListener.class);
-    protected final SyncReactor reactor;
-    private final FlowCapableNodeSnapshotDao configSnaphot;
+    private final SyncReactor reactor;
+    private final FlowCapableNodeSnapshotDao configSnapshot;
     private final FlowCapableNodeDao operationalDao;
 
-    public SimplifiedConfigListener(final SyncReactor reactor, FlowCapableNodeSnapshotDao configSnaphot,
-            FlowCapableNodeDao operationalDao) {
+    public SimplifiedConfigListener(final SyncReactor reactor,
+                                    final FlowCapableNodeSnapshotDao configSnapshot,
+                                    final FlowCapableNodeDao operationalDao) {
         this.reactor = reactor;
-        this.configSnaphot = configSnaphot;
+        this.configSnapshot = configSnapshot;
         this.operationalDao = operationalDao;
     }
 
     @Override
-    public void onDataTreeChanged(Collection<DataTreeModification<FlowCapableNode>> modifications) {
-        LOG.trace("Inventory Config changes {}", modifications.size());
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<FlowCapableNode>> modifications) {
         super.onDataTreeChanged(modifications);
     }
-    
+
     /**
-     * Compare cached operational with current config modification. If operational is not present
-     * skip calling Inventory RPCs.
-     * 
-     * @throws InterruptedException from syncup
+     * Update cache. If operational data are present, choose appropriate data and start syncup.
+     * Otherwise skip incoming change.
      */
     protected Optional<ListenableFuture<Boolean>> processNodeModification(
-            DataTreeModification<FlowCapableNode> modification) throws InterruptedException {
+            final DataTreeModification<FlowCapableNode> modification) {
         final InstanceIdentifier<FlowCapableNode> nodePath = modification.getRootPath().getRootIdentifier();
         final NodeId nodeId = PathUtil.digNodeId(nodePath);
 
-        configSnaphot.updateCache(nodeId, Optional.fromNullable(modification.getRootNode().getDataAfter()));
-
+        configSnapshot.updateCache(nodeId, Optional.fromNullable(modification.getRootNode().getDataAfter()));
 
         final Optional<FlowCapableNode> operationalNode = operationalDao.loadByNodeId(nodeId);
         if (!operationalNode.isPresent()) {
-            LOG.info("Skip syncup, {} operational is not present", nodeId.getValue());
-            return Optional.absent();// we try to reconfigure switch is alive
+            LOG.debug("Skip syncup, {} operational is not present", nodeId.getValue());
+            return Optional.absent();
         }
 
         final DataObjectModification<FlowCapableNode> configModification = modification.getRootNode();
@@ -73,65 +71,50 @@ public class SimplifiedConfigListener extends AbstractFrmSyncListener<FlowCapabl
         final FlowCapableNode dataAfter = configModification.getDataAfter();
         final ListenableFuture<Boolean> endResult;
         if (dataBefore == null && dataAfter != null) {
-            endResult = onNodeAdded(nodePath, dataBefore, dataAfter, operationalNode.get());
+            endResult = onNodeAdded(nodePath, dataAfter, operationalNode.get());
         } else if (dataBefore != null && dataAfter == null) {
-            endResult = onNodeDeleted(nodePath, dataBefore, operationalNode.get());
+            endResult = onNodeDeleted(nodePath, dataBefore);
         } else {
-            endResult = onNodeUpdated(nodePath, dataBefore, dataAfter, operationalNode.get());
+            endResult = onNodeUpdated(nodePath, dataBefore, dataAfter);
         }
 
         return Optional.of(endResult);
     }
 
     /**
-     * Add only what is missing in operational store. Config. node could be added in two situations:
-     * <ul>
-     * <li>Note very first time after restart was handled by operational listener. Syncup should
-     * calculate no delta (we don want to reconfigure switch if not necessary).</li>
-     * <li>But later the config. node could be deleted, after that config node added again. Syncup
-     * should calculate that everything needs to be added. Operational store should be empty in
-     * optimal case (but the switch could be reprogrammed by another person/system.</li>
-     * </ul>
+     * If node was added to config DS and it is already present in operational DS (connected) diff between current
+     * new configuration and actual configuration (seen in operational) should be calculated and sent to device.
      */
-    protected ListenableFuture<Boolean> onNodeAdded(InstanceIdentifier<FlowCapableNode> nodePath,
-            FlowCapableNode dataBefore, FlowCapableNode dataAfter, FlowCapableNode operationalNode)
-                    throws InterruptedException {
-        LOG.trace("onNodeAdded {}", nodePath);
-        
-        final ListenableFuture<Boolean> endResult =
-                reactor.syncup(nodePath, dataAfter, operationalNode);
-        return endResult;
+    private ListenableFuture<Boolean> onNodeAdded(final InstanceIdentifier<FlowCapableNode> nodePath,
+                                                  final FlowCapableNode dataAfter,
+                                                  final FlowCapableNode operationalNode) {
+        LOG.debug("Reconciliation {}: {}", dsType(), PathUtil.digNodeId(nodePath).getValue());
+        final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), operationalNode, LogicalDatastoreType.OPERATIONAL);
+        return reactor.syncup(nodePath, syncupEntry);
     }
 
     /**
      * Apply minimal changes very fast. For better performance needed just compare config
-     * after+before. Config listener should not be dependent on operational flows/groups while
+     * after+before. Config listener should not be dependent on operational flows/groups/meters while
      * updating config because operational store is highly async and it depends on another module in
      * system which is updating operational store (that components is also trying to solve
      * scale/performance issues on several layers).
      */
-    protected ListenableFuture<Boolean> onNodeUpdated(InstanceIdentifier<FlowCapableNode> nodePath,
-            FlowCapableNode dataBefore, FlowCapableNode dataAfter, FlowCapableNode operationalNodeNode)
-                    throws InterruptedException {
-        LOG.trace("onNodeUpdated {}", nodePath);
-        
-        final ListenableFuture<Boolean> endResult =
-                reactor.syncup(nodePath, dataAfter, dataBefore);
-        return endResult;
+    private ListenableFuture<Boolean> onNodeUpdated(final InstanceIdentifier<FlowCapableNode> nodePath,
+                                                    final FlowCapableNode dataBefore,
+                                                    final FlowCapableNode dataAfter) {
+        final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), dataBefore, dsType());
+        return reactor.syncup(nodePath, syncupEntry);
     }
 
     /**
-     * Remove values that are being deleted in the config from the switch. Note, this could be
-     * probably optimized using dedicated wipe-out RPC, but it has impact on switch if it is
-     * programmed by two person/system
+     * Remove values that are being deleted in the config from the switch.
+     * Note, this could be probably optimized using dedicated wipe-out RPC.
      */
-    protected ListenableFuture<Boolean> onNodeDeleted(InstanceIdentifier<FlowCapableNode> nodePath,
-            FlowCapableNode dataBefore, FlowCapableNode operationalNode) throws InterruptedException {
-        LOG.trace("onNodeDeleted {}", nodePath);
-        
-        final ListenableFuture<Boolean> endResult =
-                reactor.syncup(nodePath, null, dataBefore);
-        return endResult;
+    private ListenableFuture<Boolean> onNodeDeleted(final InstanceIdentifier<FlowCapableNode> nodePath,
+                                                    final FlowCapableNode dataBefore) {
+        final SyncupEntry syncupEntry = new SyncupEntry(null, dsType(), dataBefore, dsType());
+        return reactor.syncup(nodePath, syncupEntry);
     }
 
     @Override