|
9 | 9 | package org.elasticsearch.transport;
|
10 | 10 |
|
11 | 11 | import org.apache.logging.log4j.Level;
|
| 12 | +import org.apache.lucene.store.AlreadyClosedException; |
12 | 13 | import org.elasticsearch.TransportVersion;
|
13 | 14 | import org.elasticsearch.action.ActionListener;
|
| 15 | +import org.elasticsearch.action.LatchedActionListener; |
14 | 16 | import org.elasticsearch.action.OriginalIndices;
|
15 | 17 | import org.elasticsearch.action.support.ActionTestUtils;
|
16 | 18 | import org.elasticsearch.action.support.IndicesOptions;
|
@@ -1060,6 +1062,85 @@ public void onFailure(Exception e) {
|
1060 | 1062 | }
|
1061 | 1063 | }
|
1062 | 1064 |
|
| 1065 | + public void testCollectNodesConcurrentWithSettingsChanges() throws IOException { |
| 1066 | + final List<DiscoveryNode> knownNodes_c1 = new CopyOnWriteArrayList<>(); |
| 1067 | + |
| 1068 | + try ( |
| 1069 | + var c1N1 = startTransport( |
| 1070 | + "cluster_1_node_1", |
| 1071 | + knownNodes_c1, |
| 1072 | + VersionInformation.CURRENT, |
| 1073 | + TransportVersion.current(), |
| 1074 | + Settings.EMPTY |
| 1075 | + ); |
| 1076 | + var transportService = MockTransportService.createNewService( |
| 1077 | + Settings.EMPTY, |
| 1078 | + VersionInformation.CURRENT, |
| 1079 | + TransportVersion.current(), |
| 1080 | + threadPool, |
| 1081 | + null |
| 1082 | + ) |
| 1083 | + ) { |
| 1084 | + final var c1N1Node = c1N1.getLocalNode(); |
| 1085 | + knownNodes_c1.add(c1N1Node); |
| 1086 | + final var seedList = List.of(c1N1Node.getAddress().toString()); |
| 1087 | + transportService.start(); |
| 1088 | + transportService.acceptIncomingRequests(); |
| 1089 | + |
| 1090 | + try (RemoteClusterService service = new RemoteClusterService(createSettings("cluster_1", seedList), transportService)) { |
| 1091 | + service.initializeRemoteClusters(); |
| 1092 | + assertTrue(service.isCrossClusterSearchEnabled()); |
| 1093 | + final var numTasks = between(3, 5); |
| 1094 | + final var taskLatch = new CountDownLatch(numTasks); |
| 1095 | + |
| 1096 | + ESTestCase.startInParallel(numTasks, threadNumber -> { |
| 1097 | + if (threadNumber == 0) { |
| 1098 | + taskLatch.countDown(); |
| 1099 | + boolean isLinked = true; |
| 1100 | + while (taskLatch.getCount() != 0) { |
| 1101 | + final var future = new PlainActionFuture<RemoteClusterService.RemoteClusterConnectionStatus>(); |
| 1102 | + final var settings = createSettings("cluster_1", isLinked ? Collections.emptyList() : seedList); |
| 1103 | + service.updateRemoteCluster("cluster_1", settings, future); |
| 1104 | + safeGet(future); |
| 1105 | + isLinked = isLinked == false; |
| 1106 | + } |
| 1107 | + return; |
| 1108 | + } |
| 1109 | + |
| 1110 | + // Verify collectNodes() always invokes the listener, even if the node is concurrently being unlinked. |
| 1111 | + try { |
| 1112 | + for (int i = 0; i < 10; ++i) { |
| 1113 | + final var latch = new CountDownLatch(1); |
| 1114 | + final var exRef = new AtomicReference<Exception>(); |
| 1115 | + service.collectNodes(Set.of("cluster_1"), new LatchedActionListener<>(new ActionListener<>() { |
| 1116 | + @Override |
| 1117 | + public void onResponse(BiFunction<String, String, DiscoveryNode> func) { |
| 1118 | + assertEquals(c1N1Node, func.apply("cluster_1", c1N1Node.getId())); |
| 1119 | + } |
| 1120 | + |
| 1121 | + @Override |
| 1122 | + public void onFailure(Exception e) { |
| 1123 | + exRef.set(e); |
| 1124 | + } |
| 1125 | + }, latch)); |
| 1126 | + safeAwait(latch); |
| 1127 | + if (exRef.get() != null) { |
| 1128 | + assertThat( |
| 1129 | + exRef.get(), |
| 1130 | + either(instanceOf(TransportException.class)).or(instanceOf(NoSuchRemoteClusterException.class)) |
| 1131 | + .or(instanceOf(AlreadyClosedException.class)) |
| 1132 | + .or(instanceOf(NoSeedNodeLeftException.class)) |
| 1133 | + ); |
| 1134 | + } |
| 1135 | + } |
| 1136 | + } finally { |
| 1137 | + taskLatch.countDown(); |
| 1138 | + } |
| 1139 | + }); |
| 1140 | + } |
| 1141 | + } |
| 1142 | + } |
| 1143 | + |
1063 | 1144 | public void testRemoteClusterSkipIfDisconnectedSetting() {
|
1064 | 1145 | {
|
1065 | 1146 | Settings settings = Settings.builder()
|
|
0 commit comments