From 25e96a8cd3f11ce0e0a33cffbbe2aa8844967c9b Mon Sep 17 00:00:00 2001 From: Eric Zhao Date: Fri, 4 Jan 2019 14:03:55 +0800 Subject: [PATCH] Improve cluster state manager - Support stop cluster mode (`NOT-STARTED` mode) - Fix bug when updating cluster state via command API (should modify via state property) Signed-off-by: Eric Zhao --- .../sentinel/cluster/ClusterStateManager.java | 66 ++++++++++++++----- .../cluster/client/TokenClientProvider.java | 4 ++ .../EmbeddedClusterTokenServerProvider.java | 4 ++ .../ModifyClusterModeCommandHandler.java | 22 +++++-- 4 files changed, 72 insertions(+), 24 deletions(-) diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterStateManager.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterStateManager.java index 4a4b1334..3c15f87d 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterStateManager.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/ClusterStateManager.java @@ -27,7 +27,10 @@ import com.alibaba.csp.sentinel.property.SentinelProperty; import com.alibaba.csp.sentinel.util.TimeUtil; /** - *

Global tate manager for Sentinel cluster. This enables switching between cluster client and server.

+ *

+ * Global state manager for Sentinel cluster. + * This enables switching between cluster token client and server mode. + *

* * @author Eric Zhao * @since 1.4.0 @@ -36,15 +39,14 @@ public final class ClusterStateManager { public static final int CLUSTER_CLIENT = 0; public static final int CLUSTER_SERVER = 1; + public static final int CLUSTER_NOT_STARTED = -1; - private static volatile int mode = -1; + private static volatile int mode = CLUSTER_NOT_STARTED; private static volatile long lastModified = -1; private static volatile SentinelProperty stateProperty = new DynamicSentinelProperty(); private static final PropertyListener PROPERTY_LISTENER = new ClusterStatePropertyListener(); - private static final Object UPDATE_LOCK = new Object(); - static { InitExecutor.doInit(); stateProperty.addListener(PROPERTY_LISTENER); @@ -206,33 +208,61 @@ public final class ClusterStateManager { private static class ClusterStatePropertyListener implements PropertyListener { @Override public synchronized void configLoad(Integer value) { - applyState(value); + applyStateInternal(value); } @Override public synchronized void configUpdate(Integer value) { - applyState(value); + applyStateInternal(value); } } - public static boolean applyState(Integer state) { - if (state == null || state < 0) { + private static boolean applyStateInternal(Integer state) { + if (state == null || state < CLUSTER_NOT_STARTED) { return false; } if (state == mode) { return true; } - synchronized (UPDATE_LOCK) { - switch (state) { - case CLUSTER_CLIENT: - return setToClient(); - case CLUSTER_SERVER: - return setToServer(); - default: - RecordLog.warn("[ClusterStateManager] Ignoring unknown cluster state: " + state); - return false; - } + switch (state) { + case CLUSTER_CLIENT: + return setToClient(); + case CLUSTER_SERVER: + return setToServer(); + case CLUSTER_NOT_STARTED: + setStop(); + return true; + default: + RecordLog.warn("[ClusterStateManager] Ignoring unknown cluster state: " + state); + return false; + } + } + + private static void setStop() { + if (mode == CLUSTER_NOT_STARTED) { + return; } + RecordLog.info("[ClusterStateManager] Changing cluster mode to not-started"); + mode = CLUSTER_NOT_STARTED; + + sleepIfNeeded(); + lastModified = TimeUtil.currentTimeMillis(); + + stopClient(); + stopServer(); + } + + /** + * Apply given state to cluster mode. + * + * @param state valid state to apply + */ + public static void applyState(Integer state) { + stateProperty.updateValue(state); + } + + public static void markToServer() { + mode = CLUSTER_SERVER; } private static final int MIN_INTERVAL = 5 * 1000; diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/client/TokenClientProvider.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/client/TokenClientProvider.java index c46a75ec..def2f016 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/client/TokenClientProvider.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/client/TokenClientProvider.java @@ -49,5 +49,9 @@ public final class TokenClientProvider { } } + public static boolean isClientSpiAvailable() { + return getClient() != null; + } + private TokenClientProvider() {} } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/server/EmbeddedClusterTokenServerProvider.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/server/EmbeddedClusterTokenServerProvider.java index bd3da760..6b76af93 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/server/EmbeddedClusterTokenServerProvider.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/cluster/server/EmbeddedClusterTokenServerProvider.java @@ -44,5 +44,9 @@ public final class EmbeddedClusterTokenServerProvider { return server; } + public static boolean isServerSpiAvailable() { + return getServer() != null; + } + private EmbeddedClusterTokenServerProvider() {} } diff --git a/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/command/handler/cluster/ModifyClusterModeCommandHandler.java b/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/command/handler/cluster/ModifyClusterModeCommandHandler.java index 072a52b0..9841c02f 100644 --- a/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/command/handler/cluster/ModifyClusterModeCommandHandler.java +++ b/sentinel-transport/sentinel-transport-common/src/main/java/com/alibaba/csp/sentinel/command/handler/cluster/ModifyClusterModeCommandHandler.java @@ -16,6 +16,8 @@ package com.alibaba.csp.sentinel.command.handler.cluster; import com.alibaba.csp.sentinel.cluster.ClusterStateManager; +import com.alibaba.csp.sentinel.cluster.client.TokenClientProvider; +import com.alibaba.csp.sentinel.cluster.server.EmbeddedClusterTokenServerProvider; import com.alibaba.csp.sentinel.command.CommandHandler; import com.alibaba.csp.sentinel.command.CommandRequest; import com.alibaba.csp.sentinel.command.CommandResponse; @@ -33,16 +35,24 @@ public class ModifyClusterModeCommandHandler implements CommandHandler { public CommandResponse handle(CommandRequest request) { try { int mode = Integer.valueOf(request.getParam("mode")); - RecordLog.info("[ModifyClusterModeCommandHandler] Modifying cluster mode to: " + mode); - if (ClusterStateManager.applyState(mode)) { - return CommandResponse.ofSuccess("success"); - } else { - return CommandResponse.ofSuccess("failed"); + if (mode == ClusterStateManager.CLUSTER_CLIENT && !TokenClientProvider.isClientSpiAvailable()) { + return CommandResponse.ofFailure(new IllegalStateException("token client mode not available: no SPI found")); + } + if (mode == ClusterStateManager.CLUSTER_SERVER && !isClusterServerSpiAvailable()) { + return CommandResponse.ofFailure(new IllegalStateException("token server mode not available: no SPI found")); } + RecordLog.info("[ModifyClusterModeCommandHandler] Modifying cluster mode to: " + mode); + + ClusterStateManager.applyState(mode); + return CommandResponse.ofSuccess("success"); } catch (NumberFormatException ex) { - return CommandResponse.ofFailure(new IllegalArgumentException("invalid mode")); + return CommandResponse.ofFailure(new IllegalArgumentException("invalid parameter")); } catch (Exception ex) { return CommandResponse.ofFailure(ex); } } + + private boolean isClusterServerSpiAvailable() { + return EmbeddedClusterTokenServerProvider.isServerSpiAvailable(); + } }