Bug 4957 Fix blocking call to Init RoleGet 59/33259/7
authorVaclav Demcak <vdemcak@cisco.com>
Wed, 20 Jan 2016 21:53:45 +0000 (22:53 +0100)
committerJozef Bacigal <jbacigal@cisco.com>
Thu, 4 Feb 2016 10:01:36 +0000 (11:01 +0100)
* we don't want to block netty channel by init Role Get

Change-Id: I9bdf7051128fb364b9d7f1c0205c206883265a57
Signed-off-by: Jozef Bacigal <jbacigal@cisco.com>
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleContext.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java

index efa9c569eef28e7eaaad84b909fbff5d5ef4cde6..6a427c02082b7fbda87a46d56b1066490e466527 100644 (file)
@@ -7,8 +7,8 @@
  */
 package org.opendaylight.openflowplugin.api.openflow.role;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.concurrent.Future;
-import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
 
@@ -26,9 +26,8 @@ public interface RoleContext extends RoleChangeListener, RequestContextStack {
      * {@link org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService} returns
      * {@link org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException}
      * @return InitializationFuture for to know where first initial Election is done and we know role.
-     * @throws CandidateAlreadyRegisteredException - we have registered Entity so drop actual connection
      */
-    Future<OfpRole> initialization() throws CandidateAlreadyRegisteredException;
+    ListenableFuture<OfpRole> initialization();
 
     @Override
     void close();
index aaf6053930ce6a8f8196c724f33de71c4aff4ee4..1890a1a2216dbb043e6a1ad4e8cd2afebc217844 100644 (file)
@@ -15,6 +15,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
@@ -62,11 +63,15 @@ public class RoleContextImpl implements RoleContext {
     }
 
     @Override
-    public Future<OfpRole> initialization() throws CandidateAlreadyRegisteredException {
+    public ListenableFuture<OfpRole> initialization() {
         LOG.debug("Initialization requestOpenflowEntityOwnership for entity {}", entity);
-        entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
-        LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
-                .getPrimaryConnectionContext().getNodeId().getValue());
+        try {
+            entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
+            LOG.debug("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
+                    .getPrimaryConnectionContext().getNodeId().getValue());
+        } catch (final CandidateAlreadyRegisteredException e) {
+            completeInitRoleChangeFuture(null, e);
+        }
         return initRoleChangeFuture;
     }
 
@@ -78,20 +83,10 @@ public class RoleContextImpl implements RoleContext {
             // this can happen as after the disconnect, we still get a last messsage from EntityOwnershipService.
             LOG.info("Device {} is disconnected from this node. Hence not attempting a role change.",
                     deviceContext.getPrimaryConnectionContext().getNodeId());
-            if (!initRoleChangeFuture.isDone()) {
-                LOG.debug("RoleChange is not valid for initialization Entity {} anymore - Device is disconnected", entity);
-                initRoleChangeFuture.cancel(true);
-            }
+            completeInitRoleChangeFuture(null, null);
             return;
         }
 
-        if (!initRoleChangeFuture.isDone()) {
-            LOG.debug("Initialization Role for entity {} is chosed {}", entity, newRole);
-            // we don't want to wait for Device RoleChangeResponse in initial phase
-            deviceContext.onClusterRoleChange(newRole);
-            initRoleChangeFuture.set(newRole);
-        }
-
         LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
                 deviceContext.getPrimaryConnectionContext().getNodeId());
 
@@ -109,16 +104,40 @@ public class RoleContextImpl implements RoleContext {
                         deviceContext.getPrimaryConnectionContext().getNodeId());
                 deviceContext.getDeviceState().setRole(newRole);
                 deviceContext.onClusterRoleChange(newRole);
+                completeInitRoleChangeFuture(newRole, null);
             }
 
             @Override
             public void onFailure(final Throwable throwable) {
                 LOG.error("Error in setRole {} for device {} ", newRole,
                         deviceContext.getPrimaryConnectionContext().getNodeId(), throwable);
+                completeInitRoleChangeFuture(null, throwable);
             }
         });
     }
 
+    void completeInitRoleChangeFuture(@Nullable final OfpRole role, @Nullable final Throwable throwable) {
+        if (initRoleChangeFuture.isDone()) {
+            return;
+        }
+        if (!isDeviceConnected()) {
+            LOG.debug("Device {} is disconnected from this node. Hence not attempting a role change.", deviceContext
+                    .getPrimaryConnectionContext().getNodeId());
+            initRoleChangeFuture.cancel(true);
+            return;
+        }
+        if (throwable != null) {
+            LOG.warn("Connection Role change fail for entity {}", entity);
+            initRoleChangeFuture.setException(throwable);
+        } else if (role != null) {
+            LOG.debug("Initialization Role for entity {} is chosed {}", entity, role);
+            initRoleChangeFuture.set(role);
+        } else {
+            LOG.debug("Unexpected initialization Role Change close for entity {}", entity);
+            initRoleChangeFuture.cancel(true);
+        }
+    }
+
     @Override
     public void close() {
         if (entityOwnershipCandidateRegistration != null) {
index caf1ced48fe81d28ea909f0fda936b8e71cee218..2b564323caa2f794977ba88a524ec153f13eb8b8 100644 (file)
@@ -19,13 +19,18 @@ import java.util.concurrent.TimeoutException;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
+import com.google.common.util.concurrent.AsyncFunction;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
@@ -91,47 +96,36 @@ public class RoleManagerImpl implements RoleManager, EntityOwnershipListener {
         deviceContext.addDeviceContextClosedHandler(this);
         Verify.verify(contexts.putIfAbsent(roleContext.getEntity(), roleContext) == null,
                 "RoleCtx for master Node {} is still not close.", deviceContext.getDeviceState().getNodeId());
-        OfpRole role = null;
-        try {
-            role = roleContext.initialization().get(5, TimeUnit.SECONDS);
-        } catch (InterruptedException | ExecutionException | TimeoutException | CandidateAlreadyRegisteredException e) {
-            LOG.warn("Unexpected exception by DeviceConection {}. Connection has to close.", deviceContext.getDeviceState().getNodeId(), e);
-            final Optional<EntityOwnershipState> entityOwnershipStateOptional = entityOwnershipService.getOwnershipState(roleContext.getEntity());
-            if (entityOwnershipStateOptional.isPresent()) {
-                // TODO : check again who will call RoleCtx.onRoleChanged but who will call DeviceCtx#onClusterRoleChange
-                role = entityOwnershipStateOptional.get().isOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
-            } else {
-                try {
-                    deviceContext.close();
-                } catch (Exception e1) {
-                    LOG.warn("Exception during device context close. ", e);
+
+        final ListenableFuture<OfpRole> roleChangeFuture = roleContext.initialization();
+        final ListenableFuture<Void> initDeviceFuture = Futures.transform(roleChangeFuture, new AsyncFunction<OfpRole, Void>() {
+            @Override
+            public ListenableFuture<Void> apply(final OfpRole input) throws Exception {
+                final ListenableFuture<Void> nextFuture;
+                if (OfpRole.BECOMEMASTER.equals(input)) {
+                    LOG.debug("Node {} was initialized", deviceContext.getDeviceState().getNodeId());
+                    nextFuture = DeviceInitializationUtils.initializeNodeInformation(deviceContext, switchFeaturesMandatory);
+                } else {
+                    LOG.debug("Node {} we are not Master so we are going to finish.", deviceContext.getDeviceState().getNodeId());
+                    nextFuture = Futures.immediateFuture(null);
                 }
-                return;
+                return nextFuture;
             }
-        }
-        if (OfpRole.BECOMEMASTER.equals(role)) {
-            final ListenableFuture<Void> initNodeFuture = DeviceInitializationUtils.initializeNodeInformation(deviceContext, switchFeaturesMandatory);
-            Futures.addCallback(initNodeFuture, new FutureCallback<Void>() {
-                @Override
-                public void onSuccess(final Void result) {
-                    LOG.trace("Node {} was initialized", deviceContext.getDeviceState().getNodeId());
-                    getRoleContextLevelUp(deviceContext);
-                }
+        });
 
-                @Override
-                public void onFailure(final Throwable t) {
-                    LOG.warn("Node {} Initialization fail", deviceContext.getDeviceState().getNodeId(), t);
-                    try {
-                        deviceContext.close();
-                    } catch (Exception e) {
-                        LOG.warn("Exception during device context close. ", e);
-                    }
-                }
-            });
-        } else {
-            getRoleContextLevelUp(deviceContext);
-        }
+        Futures.addCallback(initDeviceFuture, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void result) {
+                LOG.debug("Initialization Node {} is done.", deviceContext.getDeviceState().getNodeId());
+                getRoleContextLevelUp(deviceContext);
+            }
 
+            @Override
+            public void onFailure(final Throwable t) {
+                LOG.warn("Unexpected error for Node {} initialization", deviceContext.getDeviceState().getNodeId(), t);
+                deviceContext.close();
+            }
+        });
     }
 
     void getRoleContextLevelUp(final DeviceContext deviceContext) {