IGNITE-17415 Fix node resolves obsolete addresses from the previously restarted and killed nodes (#10170)
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
index 869df96..a64d4c8 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
@@ -82,7 +82,7 @@
/** */
@GridToStringInclude
- private Collection<InetSocketAddress> sockAddrs;
+ private volatile Collection<InetSocketAddress> sockAddrs;
/** */
@GridToStringInclude
@@ -408,6 +408,9 @@
* @return Addresses that could be used by discovery.
*/
public Collection<InetSocketAddress> socketAddresses() {
+ if (this.sockAddrs == null)
+ sockAddrs = U.toSocketAddresses(this, discPort);
+
return sockAddrs;
}
@@ -611,8 +614,6 @@
hostNames = U.readCollection(in);
discPort = in.readInt();
- sockAddrs = U.toSocketAddresses(this, discPort);
-
Object consistentIdAttr = attrs.get(ATTR_NODE_CONSISTENT_ID);
// Cluster metrics
@@ -660,9 +661,7 @@
* Only purpose of this constructor is creating node which contains necessary data to store on disc only
* @param node to copy data from
*/
- public TcpDiscoveryNode(
- ClusterNode node
- ) {
+ public TcpDiscoveryNode(ClusterNode node) {
this.id = node.id();
this.consistentId = node.consistentId();
this.addrs = node.addresses();
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryDeadNodeAddressResolvingTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryDeadNodeAddressResolvingTest.java
new file mode 100644
index 0000000..e07aee8
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryDeadNodeAddressResolvingTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.spi.discovery.tcp;
+
+import java.util.Collection;
+import java.util.Optional;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Tests that {@link TcpDiscoveryNode} that has already left cluster,
+ * doesn't have resolved socket addresses in toplogy history that a new joining node receives.
+ */
+public class TcpDiscoveryDeadNodeAddressResolvingTest extends GridCommonAbstractTest {
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration configuration = super.getConfiguration(igniteInstanceName);
+
+ configuration.setConsistentId(igniteInstanceName);
+
+ return configuration;
+ }
+
+ /**
+ * Tests that a new node that joins the topology and receives topology history,
+ * doesn't resolve addresses of nodes that already left the topology.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void test() throws Exception {
+ startGrid(0);
+
+ IgniteEx cli = startClientGrid(1);
+ String consistentId = (String)cli.configuration().getConsistentId();
+
+ startGrid(2);
+
+ cli.close();
+
+ IgniteEx grid3 = startGrid(3);
+
+ GridDiscoveryManager discovery = grid3.context().discovery();
+ // Only grid0.
+ checkNoNode(discovery, 1, consistentId);
+
+ // grid1 must be in topology snapshots but as it has already left the cluster, its address should not be resolved.
+ checkSockAddrsNull(discovery, 2, consistentId);
+ checkSockAddrsNull(discovery, 3, consistentId);
+
+ // grid1 will not be present in these topology snapshots.
+ checkNoNode(discovery, 4, consistentId);
+ checkNoNode(discovery, 5, consistentId);
+ }
+
+ /**
+ * Checks that there is no node by consistent id in the topology history snapshot.
+ *
+ * @param disco Discovery manager.
+ * @param topology Topology version.
+ * @param consistentId Node consistent id.
+ */
+ private void checkNoNode(GridDiscoveryManager disco, int topology, String consistentId) {
+ assertFalse(findNode(disco, topology, consistentId).isPresent());
+ }
+
+ /**
+ * Checks that {@link TcpDiscoveryNode} from the topology snapshot doesn't have resolved socket addresses.
+ *
+ * @param disco Discovery manager.
+ * @param topology Topology version.
+ * @param consistentId Node consistent id.
+ * @throws Exception If failed.
+ */
+ private void checkSockAddrsNull(GridDiscoveryManager disco, int topology, String consistentId) throws Exception {
+ Optional<ClusterNode> node = findNode(disco, topology, consistentId);
+
+ assertTrue(node.isPresent());
+
+ ClusterNode clusterNode = node.get();
+
+ Object sockAddrs = GridTestUtils.getFieldValue(clusterNode, "sockAddrs");
+ assertNull(sockAddrs);
+ }
+
+ /**
+ * Finds node by consistent id in the topology history snapshot.
+ *
+ * @param disco Discovery manager.
+ * @param topology Topology version.
+ * @param consistentId Node consistent id.
+ * @return Node optional.
+ */
+ private Optional<ClusterNode> findNode(GridDiscoveryManager disco, int topology, String consistentId) {
+ Collection<ClusterNode> nodes = disco.topology(topology);
+
+ return nodes.stream().filter(node -> node.consistentId().equals(consistentId)).findFirst();
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
index 3757ce7..1264c16 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
@@ -42,6 +42,7 @@
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryClientSuspensionSelfTest;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryConcurrentStartTest;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryCoordinatorFailureTest;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryDeadNodeAddressResolvingTest;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryFailedJoinTest;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryIpFinderCleanerTest;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryIpFinderFailureTest;
@@ -180,7 +181,9 @@
DiscoverySpiDataExchangeTest.class,
- TcpDiscoveryIpFinderFailureTest.class
+ TcpDiscoveryIpFinderFailureTest.class,
+
+ TcpDiscoveryDeadNodeAddressResolvingTest.class
})
public class IgniteSpiDiscoverySelfTestSuite {
/** */
diff --git a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java
index 8701312..f58bd04 100644
--- a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java
+++ b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java
@@ -59,8 +59,10 @@
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.eclipse.jetty.security.HashLoginService;
+import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext;
import org.jetbrains.annotations.Nullable;
import org.junit.Ignore;
@@ -856,7 +858,6 @@
final AtomicBoolean stop = new AtomicBoolean();
IgniteInternalFuture<?> restarterFut = GridTestUtils.runMultiThreadedAsync(new Callable<Object>() {
- @SuppressWarnings("BusyWait")
@Override public Object call() throws Exception {
Random rnd = new Random();
@@ -1017,7 +1018,10 @@
hashLoginService.setName("Test Realm");
createRealm();
hashLoginService.setConfig("/tmp/realm.properties");
- ctx.getSecurityHandler().setLoginService(hashLoginService);
+ SecurityHandler securityHandler = ctx.getSecurityHandler();
+ // DefaultAuthenticatorFactory doesn't default to basic auth anymore.
+ securityHandler.setAuthMethod(Constraint.__BASIC_AUTH);
+ securityHandler.setLoginService(hashLoginService);
srv.setHandler(ctx);