From 277d201d5db47620b29a6a69fd99aec539e537eb Mon Sep 17 00:00:00 2001 From: Jozef Bacigal Date: Wed, 17 Aug 2016 13:52:50 +0200 Subject: [PATCH] Bug 6465 Controller goes into slave mode - Changed lifecycle service in order to create lazy initilization of context in cluster - Removed clustering initialization per context - Changed reconnect strategy if not in disconnecting state - Some performance improvements - Removed OFManager general API Change-Id: I37e8f99a0590633a3e5c179b092c6b1c65e9cb1d Signed-off-by: Jozef Bacigal --- .../api/openflow/OFPContext.java | 14 +-- .../api/openflow/OFPManager.java | 19 ---- .../api/openflow/device/DeviceManager.java | 4 +- .../ClusterInitializationPhaseHandler.java | 29 ++++++ .../handlers/ClusterLifecycleSupervisor.java | 31 ++++++ .../openflow/lifecycle/LifecycleService.java | 4 +- .../api/openflow/role/RoleManager.java | 4 +- .../api/openflow/rpc/RpcManager.java | 5 +- .../statistics/StatisticsContext.java | 2 - .../statistics/StatisticsManager.java | 3 +- .../listener/HandshakeListenerImpl.java | 4 +- .../impl/device/DeviceContextImpl.java | 37 +++++-- .../impl/device/DeviceManagerImpl.java | 11 +-- .../impl/lifecycle/LifecycleServiceImpl.java | 97 ++++++++----------- .../impl/role/RoleContextImpl.java | 32 ++++++ .../impl/role/RoleManagerImpl.java | 5 - .../impl/rpc/RpcContextImpl.java | 31 ++++-- .../impl/rpc/RpcManagerImpl.java | 6 -- .../statistics/StatisticsContextImpl.java | 57 +++++++++-- .../statistics/StatisticsManagerImpl.java | 5 - .../lifecycle/LifecycleServiceImplTest.java | 14 +-- 21 files changed, 251 insertions(+), 163 deletions(-) delete mode 100644 openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java create mode 100644 openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java create mode 100644 openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java index c16d5fafb6..fad1402451 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java @@ -9,15 +9,16 @@ package org.opendaylight.openflowplugin.api.openflow; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.RejectedExecutionException; import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterLifecycleSupervisor; /** * General API for all OFP Context */ -public interface OFPContext { +public interface OFPContext extends ClusterLifecycleSupervisor, ClusterInitializationPhaseHandler { void setState(CONTEXT_STATE contextState); @@ -38,17 +39,10 @@ public interface OFPContext { */ CONTEXT_STATE getState(); - /** - * Starting cluster services for context becoming master - */ - default void startupClusterServices() throws ExecutionException, InterruptedException { - throw new InterruptedException("Cannot start abstract service, check implementation of cluster services"); - } - /** * About to stop services in cluster not master anymore or going down * @return Future most of services need time to be closed - * @param deviceDisconnected + * @param deviceDisconnected true if clustering services stopping by device disconnect */ default ListenableFuture stopClusterServices(final boolean deviceDisconnected){ return Futures.immediateFailedFuture(new RejectedExecutionException("Cannot stop abstract services, check implementation of cluster services")); diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java deleted file mode 100644 index 1879a4c55a..0000000000 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2015 Cisco Systems, Inc. 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 org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; - -/** - * Generic API for all managers - */ -public interface OFPManager { - - T gainContext(final DeviceInfo deviceInfo); - -} diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java index d965bd94d4..d93fc9b7b4 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java @@ -8,13 +8,11 @@ package org.opendaylight.openflowplugin.api.openflow.device; -import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTerminationPhaseHandler; -import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.translator.TranslatorLibrarian; /** @@ -23,7 +21,7 @@ import org.opendaylight.openflowplugin.api.openflow.translator.TranslatorLibrari * has its own device context managed by this manager. */ public interface DeviceManager extends DeviceConnectedHandler, DeviceDisconnectedHandler, DeviceLifecycleSupervisor, - DeviceInitializationPhaseHandler, DeviceTerminationPhaseHandler, TranslatorLibrarian, AutoCloseable, OFPManager { + DeviceInitializationPhaseHandler, DeviceTerminationPhaseHandler, TranslatorLibrarian, AutoCloseable { /** diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java new file mode 100644 index 0000000000..497bb29d5b --- /dev/null +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2016 Pantheon Technologies s.r.o. 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.device.handlers; + +import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; + +/** + * Interface handles MASTER initialization on ownership change + */ +public interface ClusterInitializationPhaseHandler { + + /** + * Method for initialization cycle between contexts + * @param connectionContext to check actual connection state + */ + boolean onContextInstantiateService(final ConnectionContext connectionContext); + + /** + * Method for initial submit transaction after successful initial gathering + */ + default void initialSubmitTransaction(){ + //This method need to be override only in device context to submit initial data + } +} diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java new file mode 100644 index 0000000000..6655dafc07 --- /dev/null +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2016 Pantheon Technologies s.r.o. 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.device.handlers; + +/** + * Interface has to implement all relevant manager to correctly handling + * device context initialization when device MASTER. Methods are used for order + * handlers in initialization phase. Ordering is easily changed + * pragmatically by definition. + */ +public interface ClusterLifecycleSupervisor { + + /** + * Method sets relevant {@link ClusterInitializationPhaseHandler} for building + * handler's chain for Device mastership phase. + * @param handler handler + */ + void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler); + + default void setInitialSubmitHandler(final ClusterInitializationPhaseHandler initialSubmitHandler) { + //Need to be only set in statistics context where after successful initial gather + //tx need to be submitted + } + +} diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java index 0eca3b7d15..3084568e3c 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java @@ -11,6 +11,8 @@ package org.opendaylight.openflowplugin.api.openflow.lifecycle; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterLifecycleSupervisor; import org.opendaylight.openflowplugin.api.openflow.role.RoleContext; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext; import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext; @@ -18,7 +20,7 @@ import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext /** * Service for starting or stopping all services in plugin in cluster */ -public interface LifecycleService extends ClusterSingletonService, AutoCloseable { +public interface LifecycleService extends ClusterSingletonService, AutoCloseable, ClusterLifecycleSupervisor, ClusterInitializationPhaseHandler { /** * This method registers lifecycle service to the given provider diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleManager.java index e14631a414..2b99fc99d6 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleManager.java @@ -9,7 +9,6 @@ package org.opendaylight.openflowplugin.api.openflow.role; import com.google.common.util.concurrent.CheckedFuture; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor; @@ -22,8 +21,7 @@ public interface RoleManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, AutoCloseable, - DeviceTerminationPhaseHandler, - OFPManager { + DeviceTerminationPhaseHandler { CheckedFuture removeDeviceFromOperationalDS(final DeviceInfo deviceInfo, final int numRetries); } diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/rpc/RpcManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/rpc/RpcManager.java index 25eedcbac1..eae6757584 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/rpc/RpcManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/rpc/RpcManager.java @@ -8,7 +8,6 @@ package org.opendaylight.openflowplugin.api.openflow.rpc; -import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor; @@ -18,10 +17,8 @@ import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTermin * The RPC Manager will maintain an RPC Context for each online switch. RPC context for device is created when * {@link DeviceInitializationPhaseHandler#onDeviceContextLevelUp(DeviceInfo, org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService)} * is called. - *

- * Created by Martin Bobak <mbobak@cisco.com> on 25.2.2015. */ -public interface RpcManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, AutoCloseable, DeviceTerminationPhaseHandler, OFPManager { +public interface RpcManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, AutoCloseable, DeviceTerminationPhaseHandler { void setStatisticsRpcEnabled(boolean statisticsRpcEnabled); } diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsContext.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsContext.java index 0fbc6905d7..96df0e1455 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsContext.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsContext.java @@ -12,8 +12,6 @@ import com.google.common.util.concurrent.ListenableFuture; import io.netty.util.Timeout; import java.util.Optional; import org.opendaylight.openflowplugin.api.openflow.OFPContext; -import org.opendaylight.openflowplugin.api.openflow.OFPManager; -import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener; diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsManager.java index 8a8561db76..c56e50ca25 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsManager.java @@ -8,7 +8,6 @@ package org.opendaylight.openflowplugin.api.openflow.statistics; -import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor; @@ -18,7 +17,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTermin * Manager to start or stop scheduling statistics */ public interface StatisticsManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, - DeviceTerminationPhaseHandler, AutoCloseable, OFPManager { + DeviceTerminationPhaseHandler, AutoCloseable { /** * Start scheduling statistic gathering for given device info diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/HandshakeListenerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/HandshakeListenerImpl.java index d1de6f8a20..82ad28a2b1 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/HandshakeListenerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/HandshakeListenerImpl.java @@ -69,8 +69,8 @@ public class HandshakeListenerImpl implements HandshakeListener { LOG.debug("succeeded by getting sweep barrier after post-handshake for device {}", connectionContext.getNodeId().getValue()); try { ConnectionStatus connectionStatusResult = deviceConnectedHandler.deviceConnected(connectionContext); - if (ConnectionStatus.CLOSING.equals(connectionStatusResult)) { - connectionContext.closeConnection(false); + if (!ConnectionStatus.MAY_CONTINUE.equals(connectionStatusResult)) { + connectionContext.closeConnection(ConnectionStatus.ALREADY_CONNECTED.equals(connectionStatusResult)); } SessionStatistics.countEvent(connectionContext.getNodeId().toString(), SessionStatistics.ConnectionStatus.CONNECTION_CREATED); diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java index 6b53858e87..032f86c867 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java @@ -37,6 +37,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator; import org.opendaylight.openflowplugin.api.openflow.device.RequestContext; import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary; import org.opendaylight.openflowplugin.api.openflow.device.Xid; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.MultiMsgCollector; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; @@ -137,6 +138,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi private final DeviceInfo deviceInfo; private final ConvertorExecutor convertorExecutor; private volatile CONTEXT_STATE state; + private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; public DeviceContextImpl( @Nonnull final ConnectionContext primaryConnectionContext, @@ -538,14 +540,6 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi this.state = state; } - @Override - public void startupClusterServices() throws ExecutionException, InterruptedException { - LOG.debug("Initializing transaction chain manager for node {}", getDeviceInfo().getLOGValue()); - this.transactionChainManager.activateTransactionManager(); - LOG.debug("Waiting to get node {} information", getDeviceInfo().getLOGValue()); - DeviceInitializationUtils.initializeNodeInformation(this, switchFeaturesMandatory, this.convertorExecutor); - } - @Override public ListenableFuture stopClusterServices(boolean deviceDisconnected) { return this.transactionChainManager.deactivateTransactionManager(); @@ -578,4 +572,31 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi public boolean isSkipTableFeatures() { return this.skipTableFeatures; } + + @Override + public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) { + this.clusterInitializationPhaseHandler = handler; + } + + @Override + public boolean onContextInstantiateService(final ConnectionContext connectionContext) { + + if (getPrimaryConnectionContext().getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { + LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue()); + return false; + } + + LOG.info("Starting device context cluster services for node {}", deviceInfo.getLOGValue()); + + this.transactionChainManager.activateTransactionManager(); + + try { + DeviceInitializationUtils.initializeNodeInformation(this, switchFeaturesMandatory, this.convertorExecutor); + } catch (ExecutionException | InterruptedException e) { + LOG.warn("Device {} cannot be initialized: ", deviceInfo.getLOGValue(), e); + return false; + } + + return this.clusterInitializationPhaseHandler.onContextInstantiateService(getPrimaryConnectionContext()); + } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java index aae6b2f15b..31795d68e1 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java @@ -158,14 +158,12 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi */ if (deviceContexts.containsKey(deviceInfo)) { DeviceContext deviceContext = deviceContexts.get(deviceInfo); + LOG.warn("Node {} already connected disconnecting device. Rejecting connection", deviceInfo); if (!deviceContext.getState().equals(OFPContext.CONTEXT_STATE.TERMINATION)) { - LOG.info("Node {} already connected but context state not in TERMINATION state, replacing connection context", + LOG.warn("Node {} context state not in TERMINATION state.", connectionContext.getDeviceInfo().getLOGValue()); - deviceContext.replaceConnectionContext(connectionContext); return ConnectionStatus.ALREADY_CONNECTED; } else { - LOG.warn("Rejecting connection from node which is already connected and there exist deviceContext for it: {}", - connectionContext.getDeviceInfo().getLOGValue()); return ConnectionStatus.CLOSING; } } @@ -364,11 +362,6 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi deviceContexts.put(deviceInfo, deviceContext); } - @Override - public T gainContext(final DeviceInfo deviceInfo) { - return (T) deviceContexts.get(deviceInfo); - } - @Override public void setIsNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) { this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff; diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java index 729a3d8718..6e201b9dc6 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java @@ -1,5 +1,5 @@ -/* - * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. +/** + * Copyright (c) 2016 Pantheon Technologies s.r.o. 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, @@ -14,13 +14,13 @@ import com.google.common.util.concurrent.ListenableFuture; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration; import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.role.RoleContext; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext; @@ -38,70 +38,21 @@ public class LifecycleServiceImpl implements LifecycleService { private RoleContext roleContext; private StatisticsContext statContext; private ClusterSingletonServiceRegistration registration; + private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; @Override public void instantiateServiceInstance() { - try { - if (LOG.isDebugEnabled()) { - LOG.debug("========== Starting clustering MASTER services for node {} ==========", this.deviceContext.getDeviceInfo().getLOGValue()); - } - - if (connectionInterrupted()) { - return; - } - - LOG.info("Starting device context cluster services for node {}", getIdentifier()); - this.deviceContext.startupClusterServices(); - - if (connectionInterrupted()) { - return; - } - - LOG.info("Starting statistics context cluster services for node {}", getIdentifier()); - this.statContext.startupClusterServices(); - - if (connectionInterrupted()) { - return; - } - - LOG.info("Statistics initial gathering OK, submitting data for node {}", getIdentifier()); - this.deviceContext.initialSubmitTransaction(); - - if (connectionInterrupted()) { - return; - } - - LOG.info("Starting rpc context cluster services for node {}", getIdentifier()); - this.rpcContext.startupClusterServices(); - - if (connectionInterrupted()) { - return; - } + LOG.info("========== Starting clustering MASTER services for node {} ==========", this.deviceContext.getDeviceInfo().getLOGValue()); - LOG.info("Starting role context cluster services for node {}", getIdentifier()); - this.roleContext.startupClusterServices(); - - if (connectionInterrupted()) { - return; - } - - LOG.info("Caching flows IDs ..."); - fillDeviceFlowRegistry(); - - } catch (ExecutionException | InterruptedException e) { - LOG.warn("Cluster service {} was unable to start.", this.getIdentifier()); - this.deviceContext.shutdownConnection(); + if (this.clusterInitializationPhaseHandler.onContextInstantiateService(null)) { + LOG.info("========== Start-up clustering MASTER services for node {} was SUCCESSFUL ==========", this.deviceContext.getDeviceInfo().getLOGValue()); + } else { + LOG.warn("========== Start-up clustering MASTER services for node {} was UN-SUCCESSFUL ==========", this.deviceContext.getDeviceInfo().getLOGValue()); + this.closeConnection(); } - } - private boolean connectionInterrupted() { - if (this.deviceContext.getPrimaryConnectionContext().getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { - LOG.warn("Node {} was disconnected, will stop starting MASTER services.", this.deviceContext.getDeviceInfo().getLOGValue()); - return true; - } - return false; } @Override @@ -145,6 +96,15 @@ public class LifecycleServiceImpl implements LifecycleService { @Override public void registerService(final ClusterSingletonServiceProvider singletonServiceProvider) { + //lifecycle service -> device context -> statistics context -> rpc context -> role context -> lifecycle service + this.clusterInitializationPhaseHandler = deviceContext; + this.deviceContext.setLifecycleInitializationPhaseHandler(this.statContext); + this.statContext.setLifecycleInitializationPhaseHandler(this.rpcContext); + this.rpcContext.setLifecycleInitializationPhaseHandler(this.roleContext); + this.roleContext.setLifecycleInitializationPhaseHandler(this); + //Set initial submit handler + this.statContext.setInitialSubmitHandler(this.deviceContext); + //Register cluster singleton service this.registration = singletonServiceProvider.registerClusterSingletonService(this); } @@ -218,4 +178,23 @@ public class LifecycleServiceImpl implements LifecycleService { }); } + @Override + public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) { + this.clusterInitializationPhaseHandler = handler; + } + + @Override + public boolean onContextInstantiateService(final ConnectionContext connectionContext) { + + if (ConnectionContext.CONNECTION_STATE.RIP.equals(connectionContext.getConnectionState())) { + if (LOG.isDebugEnabled()) { + LOG.debug("Connection to the device {} was interrupted.", this.deviceContext.getDeviceInfo().getLOGValue()); + } + return false; + } + + LOG.info("Caching flows IDs ..."); + fillDeviceFlowRegistry(); + return true; + } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java index ed40598d25..0a1f81095b 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java @@ -23,8 +23,10 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; import org.opendaylight.openflowplugin.api.OFConstants; +import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.RequestContext; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.role.RoleContext; import org.opendaylight.openflowplugin.api.openflow.role.RoleManager; import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext; @@ -53,6 +55,7 @@ class RoleContextImpl implements RoleContext { private final DeviceInfo deviceInfo; private CONTEXT_STATE state; private final RoleManager myManager; + private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; RoleContextImpl(final DeviceInfo deviceInfo, final HashedWheelTimer hashedWheelTimer, @@ -181,4 +184,33 @@ class RoleContextImpl implements RoleContext { return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture); } + @Override + public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) { + this.clusterInitializationPhaseHandler = handler; + } + + @Override + public boolean onContextInstantiateService(final ConnectionContext connectionContext) { + + if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { + LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue()); + return false; + } + + Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback>() { + @Override + public void onSuccess(@Nullable RpcResult setRoleOutputRpcResult) { + if (LOG.isDebugEnabled()) { + LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue()); + } + } + + @Override + public void onFailure(final Throwable throwable) { + LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue()); + } + }); + + return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext); + } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java index e6decb4a7c..4a1ca41033 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java @@ -25,7 +25,6 @@ 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.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.openflowplugin.api.openflow.OFPContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; @@ -152,8 +151,4 @@ public class RoleManagerImpl implements RoleManager { return contexts.get(deviceInfo); } - @Override - public T gainContext(final DeviceInfo deviceInfo) { - return (T) contexts.get(deviceInfo); - } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java index 6d1954d30d..fec32b5489 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java @@ -16,15 +16,16 @@ import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Semaphore; import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; +import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.RequestContext; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext; import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy; import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider; @@ -54,6 +55,7 @@ class RpcContextImpl implements RpcContext { private final ExtensionConverterProvider extensionConverterProvider; private final ConvertorExecutor convertorExecutor; private final NotificationPublishService notificationPublishService; + private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; RpcContextImpl(final DeviceInfo deviceInfo, final RpcProviderRegistry rpcProviderRegistry, @@ -200,7 +202,24 @@ class RpcContextImpl implements RpcContext { } @Override - public void startupClusterServices() throws ExecutionException, InterruptedException { + public ListenableFuture stopClusterServices(boolean deviceDisconnected) { + MdSalRegistrationUtils.unregisterServices(this); + return Futures.immediateFuture(null); + } + + @Override + public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) { + this.clusterInitializationPhaseHandler = handler; + } + + @Override + public boolean onContextInstantiateService(final ConnectionContext connectionContext) { + + if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { + LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue()); + return false; + } + MdSalRegistrationUtils.registerServices(this, deviceContext, extensionConverterProvider, convertorExecutor); if (isStatisticsRpcEnabled) { MdSalRegistrationUtils.registerStatCompatibilityServices( @@ -209,12 +228,6 @@ class RpcContextImpl implements RpcContext { notificationPublishService, convertorExecutor); } - - } - - @Override - public ListenableFuture stopClusterServices(boolean deviceDisconnected) { - MdSalRegistrationUtils.unregisterServices(this); - return Futures.immediateFuture(null); + return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext); } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcManagerImpl.java index 22c4e18693..11f30f644f 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcManagerImpl.java @@ -16,7 +16,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.openflowplugin.api.openflow.OFPContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; @@ -118,11 +117,6 @@ public class RpcManagerImpl implements RpcManager { } } - @Override - public T gainContext(DeviceInfo deviceInfo) { - return (T) contexts.get(deviceInfo); - } - @Override public void setStatisticsRpcEnabled(boolean statisticsRpcEnabled) { diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java index 310f5842ad..13c8e99594 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java @@ -23,7 +23,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutionException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; @@ -34,6 +33,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.DeviceState; import org.opendaylight.openflowplugin.api.openflow.device.RequestContext; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener; import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext; @@ -73,6 +73,8 @@ class StatisticsContextImpl implements StatisticsContext { private volatile boolean schedulingEnabled; private volatile CONTEXT_STATE state; + private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; + private ClusterInitializationPhaseHandler initialSubmitHandler; StatisticsContextImpl(@Nonnull final DeviceInfo deviceInfo, final boolean shuttingDownStatisticsPolling, @@ -427,15 +429,6 @@ class StatisticsContextImpl implements StatisticsContext { return this.deviceInfo; } - @Override - public void startupClusterServices() throws ExecutionException, InterruptedException { - if (!this.shuttingDownStatisticsPolling) { - this.statListForCollectingInitialization(); - this.initialGatherDynamicData(); - myManager.startScheduling(deviceInfo); - } - } - @Override public ListenableFuture stopClusterServices(boolean deviceDisconnected) { myManager.stopScheduling(deviceInfo); @@ -446,4 +439,48 @@ class StatisticsContextImpl implements StatisticsContext { public LifecycleService getLifecycleService() { return lifecycleService; } + + @Override + public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) { + this.clusterInitializationPhaseHandler = handler; + } + + @Override + public boolean onContextInstantiateService(final ConnectionContext connectionContext) { + + if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { + LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue()); + return false; + } + + if (!this.shuttingDownStatisticsPolling) { + + LOG.info("Starting statistics context cluster services for node {}", deviceInfo.getLOGValue()); + + this.statListForCollectingInitialization(); + Futures.addCallback(this.initialGatherDynamicData(), new FutureCallback() { + + @Override + public void onSuccess(@Nullable Boolean aBoolean) { + initialSubmitHandler.initialSubmitTransaction(); + } + + @Override + public void onFailure(Throwable throwable) { + LOG.warn("Initial gathering statistics unsuccessful for node {}", deviceInfo.getLOGValue()); + lifecycleService.closeConnection(); + } + }); + + myManager.startScheduling(deviceInfo); + + } + + return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext); + } + + @Override + public void setInitialSubmitHandler(final ClusterInitializationPhaseHandler initialSubmitHandler) { + this.initialSubmitHandler = initialSubmitHandler; + } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsManagerImpl.java index 06e7863e3e..6d726ad071 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsManagerImpl.java @@ -30,7 +30,6 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.openflowplugin.api.openflow.OFPContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.DeviceState; @@ -307,8 +306,4 @@ public class StatisticsManagerImpl implements StatisticsManager, StatisticsManag this.deviceTerminPhaseHandler = handler; } - @Override - public T gainContext(DeviceInfo deviceInfo) { - return (T) contexts.get(deviceInfo); - } } diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java index dabde3e24d..21f3f9460b 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2016 Pantheon Technologies s.r.o. 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, @@ -20,6 +20,7 @@ import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry; import org.opendaylight.openflowplugin.api.openflow.role.RoleContext; @@ -58,6 +59,7 @@ public class LifecycleServiceImplTest { lifecycleService.setRpcContext(rpcContext); lifecycleService.setRoleContext(roleContext); lifecycleService.setStatContext(statContext); + lifecycleService.registerService(clusterSingletonServiceProvider); Mockito.when(deviceContext.getDeviceInfo()).thenReturn(deviceInfo); Mockito.when(deviceContext.getPrimaryConnectionContext()).thenReturn(connectionContext); Mockito.when(deviceContext.getDeviceFlowRegistry()).thenReturn(deviceFlowRegistry); @@ -70,11 +72,11 @@ public class LifecycleServiceImplTest { @Test public void instantiateServiceInstance() throws Exception { lifecycleService.instantiateServiceInstance(); - Mockito.verify(deviceContext).startupClusterServices(); - Mockito.verify(statContext).startupClusterServices(); - Mockito.verify(deviceContext).initialSubmitTransaction(); - Mockito.verify(rpcContext).startupClusterServices(); - Mockito.verify(roleContext).startupClusterServices(); + Mockito.verify(deviceContext).setLifecycleInitializationPhaseHandler(Mockito.any()); + Mockito.verify(statContext).setLifecycleInitializationPhaseHandler(Mockito.any()); + Mockito.verify(statContext).setInitialSubmitHandler(Mockito.any()); + Mockito.verify(rpcContext).setLifecycleInitializationPhaseHandler(Mockito.any()); + Mockito.verify(roleContext).setLifecycleInitializationPhaseHandler(Mockito.any()); } @Test -- 2.36.6