You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ir...@apache.org on 2019/08/11 22:55:11 UTC

[ignite] branch master updated: IGNITE-12036 Changing baseline via set command may cause NPEs if configured NodeFilter takes node attributes into account - Fixes #6743.

This is an automated email from the ASF dual-hosted git repository.

irakov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new e7864f1  IGNITE-12036 Changing baseline via set command may cause NPEs if configured NodeFilter takes node attributes into account - Fixes #6743.
e7864f1 is described below

commit e7864f198539f87a38e993cc68f0931dca195534
Author: alapin <la...@gmail.com>
AuthorDate: Mon Aug 12 01:54:34 2019 +0300

    IGNITE-12036 Changing baseline via set command may cause NPEs if configured NodeFilter takes node attributes into account - Fixes #6743.
    
    Signed-off-by: Ivan Rakov <ir...@apache.org>
---
 .../internal/cluster/DetachedClusterNode.java      |  4 +-
 .../ignite/internal/cluster/IgniteClusterImpl.java | 21 +++++++-
 .../distributed/CacheBaselineTopologyTest.java     | 62 +++++++++++++++++++++-
 ...niteBaselineAffinityTopologyActivationTest.java | 33 ------------
 .../apache/ignite/util/GridCommandHandlerTest.java | 21 ++++++++
 .../Cache/PersistenceTest.cs                       | 28 +++++-----
 6 files changed, 119 insertions(+), 50 deletions(-)

diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
index 2c72bb0..a3a69e1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
@@ -30,7 +30,9 @@ import org.apache.ignite.lang.IgniteProductVersion;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Representation of cluster node that isn't currently present in cluster.
+ * Representation of cluster node that either isn't currently present in cluster, or semantically detached.
+ * For example nodes returned from {@code BaselineTopology.currentBaseline()} are always considered as
+ * semantically detached, even if they are currently present in cluster.
  */
 public class DetachedClusterNode implements ClusterNode {
     /** */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
index 3659241..6249301 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
@@ -29,7 +29,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -404,6 +407,22 @@ public class IgniteClusterImpl extends ClusterGroupAdapter implements IgniteClus
             if (baselineTop.isEmpty())
                 throw new IgniteException("BaselineTopology must contain at least one node.");
 
+            List<BaselineNode> currBlT = Optional.ofNullable(ctx.state().clusterState().baselineTopology()).
+                map(BaselineTopology::currentBaseline).orElse(Collections.emptyList());
+
+            Collection<ClusterNode> srvrs = ctx.cluster().get().forServers().nodes();
+
+            for (BaselineNode node : baselineTop) {
+                Object consistentId = node.consistentId();
+
+                if (currBlT.stream().noneMatch(
+                    currBlTNode -> Objects.equals(currBlTNode.consistentId(), consistentId)) &&
+                    srvrs.stream().noneMatch(
+                        currServersNode -> Objects.equals(currServersNode.consistentId(), consistentId)))
+                    throw new IgniteException("Check arguments. Node with consistent ID [" + consistentId +
+                        "] not found in server nodes.");
+            }
+
             Collection<Object> onlineNodes = onlineBaselineNodesRequestedForRemoval(baselineTop);
 
             if (onlineNodes != null) {
@@ -473,7 +492,7 @@ public class IgniteClusterImpl extends ClusterGroupAdapter implements IgniteClus
             Collection<BaselineNode> target = new ArrayList<>(top.size());
 
             for (ClusterNode node : top) {
-                if (!node.isClient())
+                if (!node.isClient() && !node.isDaemon())
                     target.add(node);
             }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
index 93b2fbb..6d80c19 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheBaselineTopologyTest.java
@@ -28,8 +28,11 @@ import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
@@ -47,6 +50,7 @@ import org.apache.ignite.configuration.WALMode;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.cluster.DetachedClusterNode;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionFullMap;
 import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
@@ -505,7 +509,8 @@ public class CacheBaselineTopologyTest extends GridCommonAbstractTest {
 
         Set<ClusterNode> blt2 = new HashSet<>(ignite.cluster().nodes());
 
-        ignite.cluster().setBaselineTopology(baselineNodes(blt2));
+        ignite.cluster().setBaselineTopology(baselineNodes(
+            blt2.stream().filter(n -> !n.isClient()).collect(Collectors.toSet())));
 
         awaitPartitionMapExchange();
 
@@ -526,7 +531,8 @@ public class CacheBaselineTopologyTest extends GridCommonAbstractTest {
 
         Set<ClusterNode> blt3 = new HashSet<>(ignite.cluster().nodes());
 
-        ignite.cluster().setBaselineTopology(baselineNodes(blt3));
+        ignite.cluster().setBaselineTopology(baselineNodes(
+            blt3.stream().filter(n -> !n.isClient()).collect(Collectors.toSet())));
 
         awaitPartitionMapExchange();
 
@@ -1009,6 +1015,58 @@ public class CacheBaselineTopologyTest extends GridCommonAbstractTest {
             assertEquals("k=" + k, Integer.valueOf(k), cache.get(k));
     }
 
+    /**
+     * Verify that in case of setting baseline topology with offline node among others
+     * {@link IgniteException} is thrown.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    @SuppressWarnings({"unchecked", "ThrowableNotThrown"})
+    public void testSettingBaselineTopologyWithOfflineNode() throws Exception {
+        Ignite ignite = startGrids(2);
+
+        ignite.cluster().active(true);
+
+        ignite(0).createCache(defaultCacheConfiguration().setNodeFilter(
+            (IgnitePredicate<ClusterNode>)node -> node.attribute("some-attr") != null));
+
+        Collection<ClusterNode> nodes = new ArrayList<>(ignite.cluster().nodes());
+        nodes.add(new DetachedClusterNode("non-existing-node-id", null));
+
+        GridTestUtils.assertThrows(log, (Callable<Void>)() -> {
+            ignite.cluster().setBaselineTopology(nodes);
+
+            return null;
+        }, IgniteException.class, "Check arguments. Node with consistent ID [non-existing-node-id] " +
+            "not found in server nodes.");
+    }
+
+    /**
+     * Verify that in case of setting baseline topology with offline node among others {@link IgniteException} is
+     * thrown.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    @SuppressWarnings({"unchecked", "ThrowableNotThrown"})
+    public void testSettingBaselineTopologyWithOfflineNodeFromOldTopology() throws Exception {
+        Ignite ignite = startGrids(2);
+
+        ignite.cluster().active(true);
+
+        stopGrid(1);
+
+        ignite.cluster().setBaselineTopology(ignite.cluster().topologyVersion());
+
+        GridTestUtils.assertThrows(log, (Callable<Void>)() -> {
+            ignite.cluster().setBaselineTopology(ignite.cluster().topologyVersion() - 1);
+
+            return null;
+        }, IgniteException.class, "Check arguments. Node with consistent ID " +
+            "[distributed.CacheBaselineTopologyTest1] not found in server nodes.");
+    }
+
     /** */
     private Collection<BaselineNode> baselineNodes(Collection<ClusterNode> clNodes) {
         Collection<BaselineNode> res = new ArrayList<>(clNodes.size());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
index 37d44d2..6fec270 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteBaselineAffinityTopologyActivationTest.java
@@ -759,39 +759,6 @@ public class IgniteBaselineAffinityTopologyActivationTest extends GridCommonAbst
     }
 
     /**
-     * Verifies that grid is autoactivated when full BaselineTopology is preset even on one node
-     * and then all other nodes from BaselineTopology are started.
-     */
-    @Test
-    public void testAutoActivationWithBaselineTopologyPreset() throws Exception {
-        Ignite ig = startGridWithConsistentId("A");
-
-        ig.cluster().active(true);
-
-        ig.cluster().setBaselineTopology(Arrays.asList(new BaselineNode[] {
-            createBaselineNodeWithConsId("A"), createBaselineNodeWithConsId("B"), createBaselineNodeWithConsId("C")}));
-
-        stopAllGrids();
-
-        final Ignite ig1 = startGridWithConsistentId("A");
-
-        startGridWithConsistentId("B");
-
-        startGridWithConsistentId("C");
-
-        boolean activated = GridTestUtils.waitForCondition(
-            new GridAbsPredicate() {
-               @Override public boolean apply() {
-                   return ig1.cluster().active();
-               }
-            },
-            10_000
-        );
-
-        assertTrue(activated);
-    }
-
-    /**
      * Creates BaselineNode with specific attribute indicating that this node is not client.
      */
     private BaselineNode createBaselineNodeWithConsId(String consId) {
diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
index f6736cf..9833950 100644
--- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
@@ -54,6 +54,7 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteCluster;
 import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cluster.BaselineNode;
 import org.apache.ignite.cluster.ClusterNode;
@@ -2703,6 +2704,26 @@ public class GridCommandHandlerTest extends GridCommandHandlerAbstractTest {
     }
 
     /**
+     * Verify that in case of setting baseline topology with offline node among others
+     * {@link IgniteException} is thrown.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void setConsistenceIdsWithOfflineBaselineNode() throws Exception {
+        Ignite ignite = startGrids(2);
+
+        ignite.cluster().active(true);
+
+        ignite(0).createCache(defaultCacheConfiguration().setNodeFilter(
+            (IgnitePredicate<ClusterNode>)node -> node.attribute("some-attr") != null));
+
+        assertEquals(EXIT_CODE_UNEXPECTED_ERROR,
+            execute("--baseline", "set", "non-existing-node-id ," + consistentIds(ignite)));
+    }
+
+    /**
      * Test execution of --diagnostic command.
      *
      * @throws Exception if failed.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/PersistenceTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/PersistenceTest.cs
index a7f35fd..e5acbdf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/PersistenceTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/PersistenceTest.cs
@@ -250,27 +250,29 @@ namespace Apache.Ignite.Core.Tests.Cache
                 var ex = Assert.Throws<IgniteException>(() => cluster.SetBaselineTopology(2));
                 Assert.AreEqual("Changing BaselineTopology on inactive cluster is not allowed.", ex.Message);
 
-                // Set with version.
                 cluster.SetActive(true);
-                cluster.SetBaselineTopology(2);
 
-                var res = cluster.GetBaselineTopology();
-                CollectionAssert.AreEquivalent(new[] {"node1", "node2"}, res.Select(x => x.ConsistentId));
+                // Can not set baseline with offline node.
+                ex = Assert.Throws<IgniteException>(() => cluster.SetBaselineTopology(2));
+                Assert.AreEqual("Check arguments. Node with consistent ID [node2] not found in server nodes.",
+                    ex.Message);
 
                 cluster.SetBaselineTopology(1);
                 Assert.AreEqual("node1", cluster.GetBaselineTopology().Single().ConsistentId);
 
-                // Set with nodes.
-                cluster.SetBaselineTopology(res);
-                
-                res = cluster.GetBaselineTopology();
-                CollectionAssert.AreEquivalent(new[] { "node1", "node2" }, res.Select(x => x.ConsistentId));
+                // Set with node.
+                cluster.SetBaselineTopology(cluster.GetBaselineTopology());
+
+                var res = cluster.GetBaselineTopology();
+                CollectionAssert.AreEquivalent(new[] { "node1"}, res.Select(x => x.ConsistentId));
 
                 cluster.SetBaselineTopology(cluster.GetTopology(1));
                 Assert.AreEqual("node1", cluster.GetBaselineTopology().Single().ConsistentId);
 
-                // Set to two nodes.
-                cluster.SetBaselineTopology(cluster.GetTopology(2));
+                // Can not set baseline with offline node.
+                ex = Assert.Throws<IgniteException>(() => cluster.SetBaselineTopology(cluster.GetTopology(2)));
+                Assert.AreEqual("Check arguments. Node with consistent ID [node2] not found in server nodes.",
+                  ex.Message);
             }
 
             // Check auto activation on cluster restart.
@@ -279,9 +281,9 @@ namespace Apache.Ignite.Core.Tests.Cache
             {
                 var cluster = ignite.GetCluster();
                 Assert.IsTrue(cluster.IsActive());
-                
+
                 var res = cluster.GetBaselineTopology();
-                CollectionAssert.AreEquivalent(new[] { "node1", "node2" }, res.Select(x => x.ConsistentId));
+                CollectionAssert.AreEquivalent(new[] { "node1"}, res.Select(x => x.ConsistentId));
             }
 
             Environment.SetEnvironmentVariable("IGNITE_BASELINE_AUTO_ADJUST_ENABLED", null);