IGNITE-5761 Add correct message when entries are not mapped to at least one node and avoid hang on rollback
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/bcbb10d4 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/bcbb10d4 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/bcbb10d4 Branch: refs/heads/ignite-5578 Commit: bcbb10d4ed72c3ac2cd8149bb5cd148f63e95725 Parents: 995258f Author: Igor Seliverstov <[email protected]> Authored: Thu Jul 27 09:44:34 2017 +0300 Committer: Alexey Goncharuk <[email protected]> Committed: Thu Jul 27 09:44:34 2017 +0300 ---------------------------------------------------------------------- ...arOptimisticSerializableTxPrepareFuture.java | 9 + .../near/GridNearOptimisticTxPrepareFuture.java | 15 ++ .../GridNearPessimisticTxPrepareFuture.java | 9 +- .../dht/NotMappedPartitionInTxTest.java | 247 +++++++++++++++++++ .../testsuites/IgniteCacheTestSuite5.java | 2 + 5 files changed, 281 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/bcbb10d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java index 72ddc67..561c4f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java @@ -29,6 +29,7 @@ import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.cluster.ClusterTopologyException; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; @@ -611,6 +612,14 @@ public class GridNearOptimisticSerializableTxPrepareFuture extends GridNearOptim cacheCtx.affinity().nodesByKey(entry.key(), topVer) : cacheCtx.topology().nodes(cacheCtx.affinity().partition(entry.key()), topVer); + if (F.isEmpty(nodes)) { + onDone(new ClusterTopologyServerNotFoundException("Failed to map keys to nodes " + + "(partition is not mapped to any node) [key=" + entry.key() + + ", partition=" + cacheCtx.affinity().partition(entry.key()) + ", topVer=" + topVer + ']')); + + return; + } + txMapping.addMapping(nodes); ClusterNode primary = F.first(nodes); http://git-wip-us.apache.org/repos/asf/ignite/blob/bcbb10d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java index edddf7d..1e7a567 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java @@ -32,6 +32,7 @@ import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.cluster.ClusterTopologyException; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; @@ -430,6 +431,10 @@ public class GridNearOptimisticTxPrepareFuture extends GridNearOptimisticTxPrepa GridDistributedTxMapping updated = map(write, topVer, cur, topLocked, remap); + if(updated == null) + // an exception occurred while transaction mapping, stop further processing + break; + if (write.context().isNear()) hasNearCache = true; @@ -640,6 +645,16 @@ public class GridNearOptimisticTxPrepareFuture extends GridNearOptimisticTxPrepa cacheCtx.affinity().nodesByKey(entry.key(), topVer) : cacheCtx.topology().nodes(cacheCtx.affinity().partition(entry.key()), topVer); + if (F.isEmpty(nodes)) { + ClusterTopologyServerNotFoundException e = new ClusterTopologyServerNotFoundException("Failed to map " + + "keys to nodes (partition is not mapped to any node) [key=" + entry.key() + + ", partition=" + cacheCtx.affinity().partition(entry.key()) + ", topVer=" + topVer + ']'); + + onDone(e); + + return null; + } + txMapping.addMapping(nodes); ClusterNode primary = F.first(nodes); http://git-wip-us.apache.org/repos/asf/ignite/blob/bcbb10d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java index e934319..11cd9f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java @@ -27,6 +27,7 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; @@ -282,7 +283,13 @@ public class GridNearPessimisticTxPrepareFuture extends GridNearTxPrepareFutureA else nodes = cacheCtx.affinity().nodesByKey(txEntry.key(), topVer); - assert !nodes.isEmpty(); + if (F.isEmpty(nodes)) { + onDone(new ClusterTopologyServerNotFoundException("Failed to map keys to nodes (partition " + + "is not mapped to any node) [key=" + txEntry.key() + + ", partition=" + cacheCtx.affinity().partition(txEntry.key()) + ", topVer=" + topVer + ']')); + + return; + } ClusterNode primary = nodes.get(0); http://git-wip-us.apache.org/repos/asf/ignite/blob/bcbb10d4/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java new file mode 100644 index 0000000..4059660 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/NotMappedPartitionInTxTest.java @@ -0,0 +1,247 @@ +package org.apache.ignite.internal.processors.cache.distributed.dht; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.Callable; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.apache.ignite.transactions.Transaction; +import org.apache.ignite.transactions.TransactionConcurrency; +import org.apache.ignite.transactions.TransactionIsolation; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED; +import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; +import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; + +/** + */ +@SuppressWarnings({"unchecked", "ThrowableNotThrown"}) +public class NotMappedPartitionInTxTest extends GridCommonAbstractTest { + /** Cache. */ + private static final String CACHE = "testCache"; + + /** Cache 2. */ + public static final String CACHE2 = CACHE + 1; + + /** Test key. */ + private static final String TEST_KEY = "key"; + + /** Is client. */ + private boolean isClient; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + return super.getConfiguration(gridName) + .setClientMode(isClient) + .setCacheConfiguration( + new CacheConfiguration(CACHE) + .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL) + .setCacheMode(CacheMode.REPLICATED) + .setAffinity(new TestAffinity()), + new CacheConfiguration(CACHE2) + .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)); + } + + /** + * + */ + public void testOneServerOptimistic() throws Exception { + try { + isClient = false; + startGrid(0); + + isClient = true; + final IgniteEx client = startGrid(1); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, OPTIMISTIC, REPEATABLE_READ); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)"); + } + finally { + stopAllGrids(); + } + } + + /** + * + */ + public void testOneServerOptimisticSerializable() throws Exception { + try { + isClient = false; + startGrid(0); + + isClient = true; + final IgniteEx client = startGrid(1); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, OPTIMISTIC, SERIALIZABLE); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)"); + } + finally { + stopAllGrids(); + } + } + + /** + * + */ + public void testOneServerPessimistic() throws Exception { + try { + isClient = false; + startGrid(0); + + isClient = true; + final IgniteEx client = startGrid(1); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, PESSIMISTIC, READ_COMMITTED); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to lock keys (all partition nodes left the grid)"); + } + finally { + stopAllGrids(); + } + } + + /** + * + */ + public void testFourServersOptimistic() throws Exception { + try { + isClient = false; + startGrids(4); + + isClient = true; + final IgniteEx client = startGrid(4); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, OPTIMISTIC, REPEATABLE_READ); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)"); + } + finally { + stopAllGrids(); + } + } + + /** + * + */ + public void testFourServersOptimisticSerializable() throws Exception { + try { + isClient = false; + startGrids(4); + + isClient = true; + final IgniteEx client = startGrid(4); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, OPTIMISTIC, SERIALIZABLE); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to map keys to nodes (partition is not mapped to any node)"); + } + finally { + stopAllGrids(); + } + } + + /** + * + */ + public void testFourServersPessimistic() throws Exception { + try { + isClient = false; + startGrids(4); + + isClient = true; + final IgniteEx client = startGrid(4); + + GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { + @Override public Void call() throws Exception { + testNotMapped(client, PESSIMISTIC, READ_COMMITTED); + + return null; + } + }, ClusterTopologyServerNotFoundException.class, "Failed to lock keys (all partition nodes left the grid)"); + } + finally { + stopAllGrids(); + } + } + + /** + * @param client Ignite client. + */ + private void testNotMapped(IgniteEx client, TransactionConcurrency concurrency, TransactionIsolation isolation) { + IgniteCache cache2 = client.cache(CACHE2); + IgniteCache cache1 = client.cache(CACHE).withKeepBinary(); + + try(Transaction tx = client.transactions().txStart(concurrency, isolation)) { + + Map<String, Integer> param = new TreeMap<>(); + param.put(TEST_KEY + 1, 1); + param.put(TEST_KEY + 1, 3); + param.put(TEST_KEY, 3); + + cache1.put(TEST_KEY, 3); + + cache1.putAll(param); + cache2.putAll(param); + + tx.commit(); + } + } + + /** */ + private static class TestAffinity extends RendezvousAffinityFunction { + /** {@inheritDoc} */ + @Override public int partition(Object key) { + if (TEST_KEY.equals(key)) + return 1; + + return super.partition(key); + } + + /** {@inheritDoc} */ + @Override public List<ClusterNode> assignPartition(int part, List<ClusterNode> nodes, int backups, + @Nullable Map<UUID, Collection<ClusterNode>> neighborhoodCache) { + if (part == 1) + return Collections.emptyList(); + + return super.assignPartition(part, nodes, backups, neighborhoodCache); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bcbb10d4/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 1395b95..dab2b19 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 @@ -41,6 +41,7 @@ import org.apache.ignite.internal.processors.cache.distributed.GridCachePartitio import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheGroupsPartitionLossPolicySelfTest; 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.IgniteCacheAtomicProtocolTest; import org.apache.ignite.internal.processors.cache.distributed.rebalancing.CacheManualRebalancingTest; import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheSyncRebalanceModeSelfTest; @@ -94,6 +95,7 @@ public class IgniteCacheTestSuite5 extends TestSuite { suite.addTestSuite(GridCachePartitionExchangeManagerHistSizeTest.class); suite.addTestSuite(GridCachePartitionEvictionDuringReadThroughSelfTest.class); + suite.addTestSuite(NotMappedPartitionInTxTest.class); return suite; }
