You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/10/09 14:47:27 UTC
[12/21] ignite git commit: IGNITE-9785 Introduce read-only state in
local node context - Fixes #4907.
IGNITE-9785 Introduce read-only state in local node context - Fixes #4907.
Signed-off-by: Ivan Rakov <ir...@apache.org>
(cherry picked from commit 179b09b)
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7c9bd23c
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7c9bd23c
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7c9bd23c
Branch: refs/heads/ignite-2.7-master
Commit: 7c9bd23c345bb4217af5c7ae1a4afb1798072039
Parents: dfd6fcb
Author: Aleksey Plekhanov <pl...@gmail.com>
Authored: Tue Oct 9 14:33:25 2018 +0300
Committer: Ivan Rakov <ir...@apache.org>
Committed: Tue Oct 9 15:00:48 2018 +0300
----------------------------------------------------------------------
.../cache/GridCacheSharedContext.java | 17 +++
.../dht/GridDhtTopologyFutureAdapter.java | 3 +
.../datastreamer/DataStreamerImpl.java | 47 ++++++-
.../cache/ClusterReadOnlyModeAbstractTest.java | 114 ++++++++++++++++
.../cache/ClusterReadOnlyModeTest.java | 134 +++++++++++++++++++
.../testsuites/IgniteCacheTestSuite5.java | 5 +-
.../cache/ClusterReadOnlyModeSqlTest.java | 94 +++++++++++++
.../IgniteCacheWithIndexingTestSuite.java | 3 +
8 files changed, 407 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
index e4d398a..caa3d20 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
@@ -171,6 +171,9 @@ public class GridCacheSharedContext<K, V> {
/** */
private final List<IgniteChangeGlobalStateSupport> stateAwareMgrs;
+ /** Cluster is in read-only mode. */
+ private volatile boolean readOnlyMode;
+
/**
* @param kernalCtx Context.
* @param txMgr Transaction manager.
@@ -1108,4 +1111,18 @@ public class GridCacheSharedContext<K, V> {
private int dhtAtomicUpdateIndex(GridCacheVersion ver) {
return U.safeAbs(ver.hashCode()) % dhtAtomicUpdCnt.length();
}
+
+ /**
+ * @return {@code true} if cluster is in read-only mode.
+ */
+ public boolean readOnlyMode() {
+ return readOnlyMode;
+ }
+
+ /**
+ * @param readOnlyMode Read-only flag.
+ */
+ public void readOnlyMode(boolean readOnlyMode) {
+ this.readOnlyMode = readOnlyMode;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTopologyFutureAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTopologyFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTopologyFutureAdapter.java
index 539fef4..9214308 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTopologyFutureAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTopologyFutureAdapter.java
@@ -97,6 +97,9 @@ public abstract class GridDhtTopologyFutureAdapter extends GridFutureAdapter<Aff
cctx.name());
}
+ if (cctx.shared().readOnlyMode() && !read)
+ return new IgniteCheckedException("Failed to perform cache operation (cluster is in read only mode)" );
+
if (grp.needsRecovery() || grp.topologyValidator() != null) {
CacheValidation validation = grpValidRes.get(grp.groupId());
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java
index bf1e13d..e86f653 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java
@@ -85,10 +85,10 @@ import org.apache.ignite.internal.processors.cache.GridCacheUtils;
import org.apache.ignite.internal.processors.cache.IgniteCacheFutureImpl;
import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
-import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
import org.apache.ignite.internal.processors.dr.GridDrType;
@@ -725,7 +725,7 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
keys.add(new KeyCacheObjectWrapper(e.getKey()));
}
- load0(entries, fut, keys, 0);
+ load0(entries, fut, keys, 0, null, null);
}
/** {@inheritDoc} */
@@ -798,13 +798,18 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
* @param resFut Result future.
* @param activeKeys Active keys.
* @param remaps Remaps count.
+ * @param remapNode Node for remap. In case update with {@code allowOverride() == false} fails on one node,
+ * we don't need to send update request to all affinity nodes again, if topology version does not changed.
+ * @param remapTopVer Topology version.
*/
private void load0(
Collection<? extends DataStreamerEntry> entries,
final GridFutureAdapter<Object> resFut,
@Nullable final Collection<KeyCacheObjectWrapper> activeKeys,
- final int remaps
- ) {
+ final int remaps,
+ ClusterNode remapNode,
+ AffinityTopologyVersion remapTopVer
+ ) {
try {
assert entries != null;
@@ -876,7 +881,10 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
if (key.partition() == -1)
key.partition(cctx.affinity().partition(key, false));
- nodes = nodes(key, topVer, cctx);
+ if (!allowOverwrite() && remapNode != null && F.eq(topVer, remapTopVer))
+ nodes = Collections.singletonList(remapNode);
+ else
+ nodes = nodes(key, topVer, cctx);
}
catch (IgniteCheckedException e) {
resFut.onDone(e);
@@ -903,6 +911,7 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
}
for (final Map.Entry<ClusterNode, Collection<DataStreamerEntry>> e : mappings.entrySet()) {
+ final ClusterNode node = e.getKey();
final UUID nodeId = e.getKey().id();
Buffer buf = bufMappings.get(nodeId);
@@ -964,7 +973,7 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
if (cancelled)
closedException();
- load0(entriesForNode, resFut, activeKeys, remaps + 1);
+ load0(entriesForNode, resFut, activeKeys, remaps + 1, node, topVer);
}
catch (Throwable ex) {
resFut.onDone(
@@ -2195,12 +2204,27 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
if (internalCache.isNear())
internalCache = internalCache.context().near().dht();
- GridCacheContext cctx = internalCache.context();
+ GridCacheContext<?, ?> cctx = internalCache.context();
+
+/* todo: uncomment this and remove topFut choosing logic below after IGNITE-9550 race is fixed
+ GridDhtTopologyFuture topFut = cctx.shared().exchange().lastFinishedFuture();
+ AffinityTopologyVersion topVer = topFut.topologyVersion();
+*/
AffinityTopologyVersion topVer = cctx.isLocal() ?
cctx.affinity().affinityTopologyVersion() :
cctx.shared().exchange().readyAffinityVersion();
+ GridDhtTopologyFuture topFut = (GridDhtTopologyFuture)cctx.shared().exchange().affinityReadyFuture(topVer);
+
+ if (topFut == null) {
+ // Exchange for newer topology version is already in progress, let's try to use last finished future.
+ GridDhtTopologyFuture lastFinishedFut = cctx.shared().exchange().lastFinishedFuture();
+
+ if (F.eq(lastFinishedFut.topologyVersion(), topVer))
+ topFut = lastFinishedFut;
+ }
+
GridCacheVersion ver = cctx.versions().isolatedStreamerVersion();
long ttl = CU.TTL_ETERNAL;
@@ -2260,6 +2284,15 @@ public class DataStreamerImpl<K, V> implements IgniteDataStreamer<K, V>, Delayed
expiryTime = CU.toExpireTime(ttl);
}
+ if (topFut != null) {
+ topFut.get();
+
+ Throwable err = topFut.validateCache(cctx, false, false, entry.key(), null);
+
+ if (err != null)
+ throw new IgniteCheckedException(err);
+ }
+
boolean primary = cctx.affinity().primaryByKey(cctx.localNode(), entry.key(), topVer);
entry.initialValue(e.getValue(),
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
new file mode 100644
index 0000000..7cb9649
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeAbstractTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+
+/**
+ *
+ */
+public class ClusterReadOnlyModeAbstractTest extends GridCommonAbstractTest {
+ /** */
+ private static final int SRVS = 3;
+
+ /** Replicated atomic cache. */
+ private static final String REPL_ATOMIC_CACHE = "repl_atomic_cache";
+
+ /** Replicated transactional cache. */
+ private static final String REPL_TX_CACHE = "repl_tx_cache";
+
+ /** Partitioned atomic cache. */
+ private static final String PART_ATOMIC_CACHE = "part_atomic_cache";
+
+ /** Partitioned transactional cache. */
+ private static final String PART_TX_CACHE = "part_tx_cache";
+
+ /** Cache names. */
+ protected static final Collection<String> CACHE_NAMES = F.asList(REPL_ATOMIC_CACHE, REPL_TX_CACHE,
+ PART_ATOMIC_CACHE, PART_TX_CACHE);
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ startGridsMultiThreaded(SRVS);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ changeClusterReadOnlyMode(false);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setCacheConfiguration(
+ cacheConfiguration(REPL_ATOMIC_CACHE, REPLICATED, ATOMIC, null),
+ cacheConfiguration(REPL_TX_CACHE, REPLICATED, TRANSACTIONAL, null),
+ cacheConfiguration(PART_ATOMIC_CACHE, PARTITIONED, ATOMIC, "part_grp"),
+ cacheConfiguration(PART_TX_CACHE, PARTITIONED, TRANSACTIONAL, "part_grp")
+ );
+
+ return cfg;
+ }
+
+ /**
+ * @param cacheMode Cache mode.
+ * @param atomicityMode Atomicity mode.
+ * @param grpName Cache group name.
+ */
+ private CacheConfiguration<Integer, Integer> cacheConfiguration(String name, CacheMode cacheMode,
+ CacheAtomicityMode atomicityMode, String grpName) {
+ return new CacheConfiguration<Integer, Integer>()
+ .setName(name)
+ .setCacheMode(cacheMode)
+ .setAtomicityMode(atomicityMode)
+ .setGroupName(grpName)
+ .setQueryEntities(Collections.singletonList(new QueryEntity(Integer.class, Integer.class)));
+ }
+
+ /**
+ * Change read only mode on all nodes.
+ *
+ * @param readOnly Read only.
+ */
+ protected void changeClusterReadOnlyMode(boolean readOnly) {
+ for (int idx = 0; idx < SRVS; idx++) {
+ IgniteEx ignite = grid(idx);
+
+ ignite.context().cache().context().readOnlyMode(readOnly);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeTest.java
new file mode 100644
index 0000000..ab57614
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.Random;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.internal.processors.datastreamer.DataStreamerImpl;
+import org.apache.ignite.internal.util.typedef.G;
+
+/**
+ * Tests cache get/put/remove and data streaming in read-only cluster mode.
+ */
+public class ClusterReadOnlyModeTest extends ClusterReadOnlyModeAbstractTest {
+ /**
+ * Tests cache get/put/remove.
+ */
+ public void testCacheGetPutRemove() {
+ assertCachesReadOnlyMode(false);
+
+ changeClusterReadOnlyMode(true);
+
+ assertCachesReadOnlyMode(true);
+
+ changeClusterReadOnlyMode(false);
+
+ assertCachesReadOnlyMode(false);
+ }
+
+ /**
+ * Tests data streamer.
+ */
+ public void testDataStreamerReadOnly() {
+ assertDataStreamerReadOnlyMode(false);
+
+ changeClusterReadOnlyMode(true);
+
+ assertDataStreamerReadOnlyMode(true);
+
+ changeClusterReadOnlyMode(false);
+
+ assertDataStreamerReadOnlyMode(false);
+ }
+
+ /**
+ * Asserts that all caches in read-only or in read/write mode on all nodes.
+ *
+ * @param readOnly If {@code true} then cache must be in read only mode, else in read/write mode.
+ */
+ private void assertCachesReadOnlyMode(boolean readOnly) {
+ Random rnd = new Random();
+
+ for (Ignite ignite : G.allGrids()) {
+ for (String cacheName : CACHE_NAMES) {
+ IgniteCache<Integer, Integer> cache = ignite.cache(cacheName);
+
+ for (int i = 0; i < 10; i++) {
+ cache.get(rnd.nextInt(100)); // All gets must succeed.
+
+ if (readOnly) {
+ // All puts must fail.
+ try {
+ cache.put(rnd.nextInt(100), rnd.nextInt());
+
+ fail("Put must fail for cache " + cacheName);
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ // All removes must fail.
+ try {
+ cache.remove(rnd.nextInt(100));
+
+ fail("Remove must fail for cache " + cacheName);
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+ }
+ else {
+ cache.put(rnd.nextInt(100), rnd.nextInt()); // All puts must succeed.
+
+ cache.remove(rnd.nextInt(100)); // All removes must succeed.
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param readOnly If {@code true} then data streamer must fail, else succeed.
+ */
+ private void assertDataStreamerReadOnlyMode(boolean readOnly) {
+ Random rnd = new Random();
+
+ for (Ignite ignite : G.allGrids()) {
+ for (String cacheName : CACHE_NAMES) {
+ boolean failed = false;
+
+ try (IgniteDataStreamer<Integer, Integer> streamer = ignite.dataStreamer(cacheName)) {
+ for (int i = 0; i < 10; i++) {
+ ((DataStreamerImpl)streamer).maxRemapCount(5);
+
+ streamer.addData(rnd.nextInt(1000), rnd.nextInt());
+ }
+ }
+ catch (CacheException ignored) {
+ failed = true;
+ }
+
+ if (failed != readOnly)
+ fail("Streaming to " + cacheName + " must " + (readOnly ? "fail" : "succeed"));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
index dafc44f..a583317 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite5.java
@@ -29,6 +29,7 @@ import org.apache.ignite.internal.processors.cache.CacheKeepBinaryTransactionTes
import org.apache.ignite.internal.processors.cache.CacheNearReaderUpdateTest;
import org.apache.ignite.internal.processors.cache.CacheRebalancingSelfTest;
import org.apache.ignite.internal.processors.cache.CacheSerializableTransactionsTest;
+import org.apache.ignite.internal.processors.cache.ClusterReadOnlyModeTest;
import org.apache.ignite.internal.processors.cache.ClusterStatePartitionedSelfTest;
import org.apache.ignite.internal.processors.cache.ClusterStateReplicatedSelfTest;
import org.apache.ignite.internal.processors.cache.ConcurrentCacheStartTest;
@@ -43,10 +44,7 @@ import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheGroups
import org.apache.ignite.internal.processors.cache.distributed.IgniteCachePartitionLossPolicySelfTest;
import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheTxIteratorSelfTest;
import org.apache.ignite.internal.processors.cache.distributed.dht.NotMappedPartitionInTxTest;
-import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridCacheAtomicPreloadSelfTest;
import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.IgniteCacheAtomicProtocolTest;
-import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.IgniteCacheContainsKeyColocatedAtomicSelfTest;
-import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.IgniteCacheContainsKeyNearAtomicSelfTest;
import org.apache.ignite.internal.processors.cache.distributed.rebalancing.CacheManualRebalancingTest;
import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheSyncRebalanceModeSelfTest;
import org.apache.ignite.internal.processors.cache.store.IgniteCacheWriteBehindNoUpdateSelfTest;
@@ -82,6 +80,7 @@ public class IgniteCacheTestSuite5 extends TestSuite {
suite.addTestSuite(ClusterStatePartitionedSelfTest.class);
suite.addTestSuite(ClusterStateReplicatedSelfTest.class);
+ suite.addTestSuite(ClusterReadOnlyModeTest.class);
suite.addTestSuite(IgniteCachePartitionLossPolicySelfTest.class);
suite.addTestSuite(IgniteCacheGroupsPartitionLossPolicySelfTest.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeSqlTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeSqlTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeSqlTest.java
new file mode 100644
index 0000000..d431f73
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ClusterReadOnlyModeSqlTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.Random;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.util.typedef.G;
+
+/**
+ * Tests SQL queries in read-only cluster mode.
+ */
+public class ClusterReadOnlyModeSqlTest extends ClusterReadOnlyModeAbstractTest {
+ /**
+ *
+ */
+ public void testSqlReadOnly() {
+ assertSqlReadOnlyMode(false);
+
+ changeClusterReadOnlyMode(true);
+
+ assertSqlReadOnlyMode(true);
+
+ changeClusterReadOnlyMode(false);
+
+ assertSqlReadOnlyMode(false);
+ }
+
+ /**
+ * @param readOnly If {@code true} then data modification SQL queries must fail, else succeed.
+ */
+ private void assertSqlReadOnlyMode(boolean readOnly) {
+ Random rnd = new Random();
+
+ for (Ignite ignite : G.allGrids()) {
+ for (String cacheName : CACHE_NAMES) {
+ IgniteCache<Integer, Integer> cache = ignite.cache(cacheName);
+
+ try (FieldsQueryCursor<?> cur = cache.query(new SqlFieldsQuery("SELECT * FROM Integer"))) {
+ cur.getAll();
+ }
+
+ boolean failed = false;
+
+ try (FieldsQueryCursor<?> cur = cache.query(new SqlFieldsQuery("DELETE FROM Integer"))) {
+ cur.getAll();
+ }
+ catch (CacheException ex) {
+ if (!readOnly)
+ log.error("Failed to delete data", ex);
+
+ failed = true;
+ }
+
+ if (failed != readOnly)
+ fail("SQL delete from " + cacheName + " must " + (readOnly ? "fail" : "succeed"));
+
+ failed = false;
+
+ try (FieldsQueryCursor<?> cur = cache.query(new SqlFieldsQuery(
+ "INSERT INTO Integer(_KEY, _VAL) VALUES (?, ?)").setArgs(rnd.nextInt(1000), rnd.nextInt()))) {
+ cur.getAll();
+ }
+ catch (CacheException ex) {
+ if (!readOnly)
+ log.error("Failed to insert data", ex);
+
+ failed = true;
+ }
+
+ if (failed != readOnly)
+ fail("SQL insert into " + cacheName + " must " + (readOnly ? "fail" : "succeed"));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c9bd23c/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
index e351cb6..8517ebb 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
@@ -27,6 +27,7 @@ import org.apache.ignite.internal.processors.cache.CacheQueryAfterDynamicCacheSt
import org.apache.ignite.internal.processors.cache.CacheQueryFilterExpiredTest;
import org.apache.ignite.internal.processors.cache.CacheRandomOperationsMultithreadedTest;
import org.apache.ignite.internal.processors.cache.ClientReconnectAfterClusterRestartTest;
+import org.apache.ignite.internal.processors.cache.ClusterReadOnlyModeSqlTest;
import org.apache.ignite.internal.processors.cache.GridCacheOffHeapSelfTest;
import org.apache.ignite.internal.processors.cache.GridCacheOffheapIndexEntryEvictTest;
import org.apache.ignite.internal.processors.cache.GridCacheOffheapIndexGetSelfTest;
@@ -90,6 +91,8 @@ public class IgniteCacheWithIndexingTestSuite extends TestSuite {
suite.addTestSuite(BinaryTypeMismatchLoggingTest.class);
+ suite.addTestSuite(ClusterReadOnlyModeSqlTest.class);
+
return suite;
}
}