diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientClusterImpl.java index 6dfc5bf483e65..e2fba8e0113b7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientClusterImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientClusterImpl.java @@ -26,7 +26,7 @@ /** * Implementation of {@link ClientCluster}. */ -class ClientClusterImpl extends ClientClusterGroupImpl implements ClientCluster { +public class ClientClusterImpl extends ClientClusterGroupImpl implements ClientCluster { /** Default cluster group. */ private final ClientClusterGroupImpl dfltClusterGrp; @@ -54,6 +54,20 @@ class ClientClusterImpl extends ClientClusterGroupImpl implements ClientCluster /** {@inheritDoc} */ @Override public void state(ClusterState newState) throws ClientException { + state(newState, true); + } + + /** + * Changes current cluster state to given {@code newState} cluster state. + *

+ * NOTE: + * Deactivation clears in-memory caches (without persistence) including the system caches. + * + * @param newState New cluster state. + * @param forceDeactivation If {@code true}, cluster deactivation will be forced. + * @throws ClientException If change state operation failed. + */ + public void state(ClusterState newState, boolean forceDeactivation) throws ClientException { try { ch.service(ClientOperation.CLUSTER_CHANGE_STATE, req -> { @@ -67,6 +81,14 @@ class ClientClusterImpl extends ClientClusterGroupImpl implements ClientCluster } req.out().writeByte((byte)newState.ordinal()); + + if (protocolCtx.isFeatureSupported(ProtocolBitmaskFeature.FORCE_DEACTIVATION_FLAG)) + req.out().writeBoolean(forceDeactivation); + else if (!forceDeactivation) { + throw new ClientFeatureNotSupportedByServerException( + "Force deactivation flag is not supported by the server" + ); + } }, null ); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolBitmaskFeature.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolBitmaskFeature.java index 1a0fb9d714829..e3ff013fd8604 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolBitmaskFeature.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolBitmaskFeature.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.EnumSet; import org.apache.ignite.client.ClientServices; +import org.apache.ignite.cluster.ClusterState; /** * Defines supported bitmask features for thin client. @@ -83,7 +84,10 @@ public enum ProtocolBitmaskFeature { CACHE_INVOKE(17), /** Transaction aware queries. */ - TX_AWARE_QUERIES(18); + TX_AWARE_QUERIES(18), + + /** Force deactivation flag. See {@link org.apache.ignite.client.ClientCluster#state(ClusterState, boolean)}. */ + FORCE_DEACTIVATION_FLAG(19); /** */ private static final EnumSet ALL_FEATURES_AS_ENUM_SET = diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java index d51b8eaaa743e..dc3187b955453 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java @@ -19,6 +19,7 @@ import java.util.EnumSet; import org.apache.ignite.client.ClientServices; +import org.apache.ignite.cluster.ClusterState; import org.apache.ignite.internal.ThinProtocolFeature; import org.apache.ignite.internal.client.thin.TcpClientCache; @@ -81,7 +82,10 @@ public enum ClientBitmaskFeature implements ThinProtocolFeature { CACHE_INVOKE(17), /** Transaction aware queries. */ - TX_AWARE_QUERIES(18); + TX_AWARE_QUERIES(18), + + /** Force deactivation flag. See {@link org.apache.ignite.client.ClientCluster#state(ClusterState, boolean)}. */ + FORCE_DEACTIVATION_FLAG(19); /** */ private static final EnumSet ALL_FEATURES_AS_ENUM_SET = diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java index 60a897685d353..8684a6a1fed36 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java @@ -615,7 +615,7 @@ public ClientListenerRequest decode(BinaryReaderExImpl reader) { return new ClientClusterGetStateRequest(reader); case OP_CLUSTER_CHANGE_STATE: - return new ClientClusterChangeStateRequest(reader); + return new ClientClusterChangeStateRequest(reader, protocolCtx); case OP_CLUSTER_CHANGE_WAL_STATE: return new ClientClusterWalChangeStateRequest(reader); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterChangeStateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterChangeStateRequest.java index e8b737962c4d7..126f056591b1d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterChangeStateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterChangeStateRequest.java @@ -17,12 +17,17 @@ package org.apache.ignite.internal.processors.platform.client.cluster; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; import org.apache.ignite.binary.BinaryRawReader; import org.apache.ignite.cluster.ClusterState; import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext; +import org.apache.ignite.internal.processors.platform.client.ClientProtocolContext; import org.apache.ignite.internal.processors.platform.client.ClientRequest; import org.apache.ignite.internal.processors.platform.client.ClientResponse; +import static org.apache.ignite.internal.processors.platform.client.ClientBitmaskFeature.FORCE_DEACTIVATION_FLAG; + /** * Cluster status request. */ @@ -30,21 +35,35 @@ public class ClientClusterChangeStateRequest extends ClientRequest { /** Next state. */ private final ClusterState state; + /** If {@code true}, cluster deactivation will be forced. */ + private final boolean forceDeactivation; + /** * Constructor. * * @param reader Reader. */ - public ClientClusterChangeStateRequest(BinaryRawReader reader) { + public ClientClusterChangeStateRequest(BinaryRawReader reader, ClientProtocolContext protocolCtx) { super(reader); state = ClusterState.fromOrdinal(reader.readByte()); + forceDeactivation = !protocolCtx.isFeatureSupported(FORCE_DEACTIVATION_FLAG) || reader.readBoolean(); } /** {@inheritDoc} */ @Override public ClientResponse process(ClientConnectionContext ctx) { - ctx.kernalContext().grid().cluster().state(state); + try { + ctx.kernalContext().state().changeGlobalState( + state, + forceDeactivation, + ctx.kernalContext().cluster().get().forServers().nodes(), + false + ).get(); - return new ClientResponse(requestId()); + return new ClientResponse(requestId()); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/ClusterApiTest.java b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/ClusterApiTest.java index 5540ea3833a60..5d031dca3d9f9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/ClusterApiTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/ClusterApiTest.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.client.thin; import org.apache.ignite.IgniteCluster; +import org.apache.ignite.IgniteException; +import org.apache.ignite.client.ClientCacheConfiguration; import org.apache.ignite.client.ClientCluster; import org.apache.ignite.client.IgniteClient; import org.apache.ignite.cluster.ClusterState; @@ -26,6 +28,8 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.junit.Test; +import static org.apache.ignite.testframework.GridTestUtils.assertThrows; + /** * Checks cluster state/WAL state operations for thin client. */ @@ -35,7 +39,9 @@ public class ClusterApiTest extends AbstractThinClientTest { return super.getConfiguration(igniteInstanceName) .setDataStorageConfiguration(new DataStorageConfiguration() .setDefaultDataRegionConfiguration(new DataRegionConfiguration() - .setPersistenceEnabled(true))) + .setPersistenceEnabled(true)) + .setDataRegionConfigurations(new DataRegionConfiguration() + .setName("non-persistent"))) .setClusterStateOnStart(ClusterState.INACTIVE); } @@ -73,6 +79,30 @@ public void testClusterState() throws Exception { } } + /** + * Test change cluster state operation by thin client. + */ + @Test + public void testForceDeactivation() { + try (IgniteClient client = startClient(0)) { + client.cluster().state(ClusterState.ACTIVE); + + client.getOrCreateCache(new ClientCacheConfiguration() + .setName("non-persistent-cache") + .setDataRegionName("non-persistent")); + + assertThrows(log, () -> ((ClientClusterImpl)client.cluster()).state(ClusterState.INACTIVE, false), + IgniteException.class, "Deactivation stopped. " + + "Deactivation clears in-memory caches (without persistence) including the system caches."); + + assertTrue(grid(0).cluster().state().active()); + + ((ClientClusterImpl)client.cluster()).state(ClusterState.INACTIVE, true); + + assertFalse(grid(0).cluster().state().active()); + } + } + /** * Test change WAL state for cache operation by thin client. */