|
8 | 8 | package org.elasticsearch.xpack.esql.plugin; |
9 | 9 |
|
10 | 10 | import org.elasticsearch.ExceptionsHelper; |
| 11 | +import org.elasticsearch.TransportVersion; |
11 | 12 | import org.elasticsearch.action.ActionListener; |
12 | 13 | import org.elasticsearch.action.NoShardAvailableActionException; |
13 | 14 | import org.elasticsearch.action.OriginalIndices; |
14 | 15 | import org.elasticsearch.action.search.SearchRequest; |
15 | 16 | import org.elasticsearch.action.support.PlainActionFuture; |
16 | 17 | import org.elasticsearch.cluster.node.DiscoveryNode; |
17 | 18 | import org.elasticsearch.cluster.node.DiscoveryNodeUtils; |
| 19 | +import org.elasticsearch.cluster.node.VersionInformation; |
18 | 20 | import org.elasticsearch.common.breaker.CircuitBreaker.Durability; |
19 | 21 | import org.elasticsearch.common.breaker.CircuitBreakingException; |
20 | 22 | import org.elasticsearch.common.settings.Settings; |
|
29 | 31 | import org.elasticsearch.tasks.CancellableTask; |
30 | 32 | import org.elasticsearch.tasks.Task; |
31 | 33 | import org.elasticsearch.tasks.TaskId; |
| 34 | +import org.elasticsearch.test.transport.MockTransportService; |
32 | 35 | import org.elasticsearch.threadpool.FixedExecutorBuilder; |
33 | 36 | import org.elasticsearch.threadpool.TestThreadPool; |
34 | 37 | import org.elasticsearch.transport.TransportService; |
|
52 | 55 | import java.util.function.Function; |
53 | 56 | import java.util.stream.Collectors; |
54 | 57 |
|
| 58 | +import static org.elasticsearch.cluster.node.DiscoveryNodeRole.DATA_COLD_NODE_ROLE; |
| 59 | +import static org.elasticsearch.cluster.node.DiscoveryNodeRole.DATA_FROZEN_NODE_ROLE; |
| 60 | +import static org.elasticsearch.cluster.node.DiscoveryNodeRole.DATA_HOT_NODE_ROLE; |
| 61 | +import static org.elasticsearch.cluster.node.DiscoveryNodeRole.DATA_WARM_NODE_ROLE; |
55 | 62 | import static org.elasticsearch.xpack.esql.plugin.DataNodeRequestSender.NodeRequest; |
| 63 | +import static org.hamcrest.Matchers.anyOf; |
56 | 64 | import static org.hamcrest.Matchers.containsString; |
57 | 65 | import static org.hamcrest.Matchers.equalTo; |
58 | 66 | import static org.hamcrest.Matchers.hasSize; |
59 | 67 | import static org.hamcrest.Matchers.in; |
60 | 68 | import static org.hamcrest.Matchers.not; |
61 | | -import static org.mockito.Mockito.mock; |
62 | | -import static org.mockito.Mockito.when; |
63 | 69 |
|
64 | 70 | public class DataNodeRequestSenderTests extends ComputeTestCase { |
65 | 71 |
|
66 | 72 | private TestThreadPool threadPool; |
67 | 73 | private Executor executor = null; |
68 | 74 | private static final String ESQL_TEST_EXECUTOR = "esql_test_executor"; |
69 | 75 |
|
70 | | - private final DiscoveryNode node1 = DiscoveryNodeUtils.create("node-1"); |
71 | | - private final DiscoveryNode node2 = DiscoveryNodeUtils.create("node-2"); |
72 | | - private final DiscoveryNode node3 = DiscoveryNodeUtils.create("node-3"); |
73 | | - private final DiscoveryNode node4 = DiscoveryNodeUtils.create("node-4"); |
74 | | - private final DiscoveryNode node5 = DiscoveryNodeUtils.create("node-5"); |
| 76 | + private final DiscoveryNode node1 = DiscoveryNodeUtils.builder("node-1").roles(Set.of(DATA_HOT_NODE_ROLE)).build(); |
| 77 | + private final DiscoveryNode node2 = DiscoveryNodeUtils.builder("node-2").roles(Set.of(DATA_HOT_NODE_ROLE)).build(); |
| 78 | + private final DiscoveryNode node3 = DiscoveryNodeUtils.builder("node-3").roles(Set.of(DATA_HOT_NODE_ROLE)).build(); |
| 79 | + private final DiscoveryNode node4 = DiscoveryNodeUtils.builder("node-4").roles(Set.of(DATA_HOT_NODE_ROLE)).build(); |
| 80 | + private final DiscoveryNode node5 = DiscoveryNodeUtils.builder("node-5").roles(Set.of(DATA_HOT_NODE_ROLE)).build(); |
75 | 81 | private final ShardId shard1 = new ShardId("index", "n/a", 1); |
76 | 82 | private final ShardId shard2 = new ShardId("index", "n/a", 2); |
77 | 83 | private final ShardId shard3 = new ShardId("index", "n/a", 3); |
@@ -371,6 +377,37 @@ public void testSkipRemovesPriorNonFatalErrors() { |
371 | 377 | assertThat(response.failedShards, equalTo(0)); |
372 | 378 | } |
373 | 379 |
|
| 380 | + public void testQueryHotShardsFirst() { |
| 381 | + var targetShards = shuffledList( |
| 382 | + List.of( |
| 383 | + targetShard(shard1, node1), |
| 384 | + targetShard(shard2, DiscoveryNodeUtils.builder("node-2").roles(Set.of(DATA_WARM_NODE_ROLE)).build()), |
| 385 | + targetShard(shard3, DiscoveryNodeUtils.builder("node-3").roles(Set.of(DATA_COLD_NODE_ROLE)).build()), |
| 386 | + targetShard(shard4, DiscoveryNodeUtils.builder("node-4").roles(Set.of(DATA_FROZEN_NODE_ROLE)).build()) |
| 387 | + ) |
| 388 | + ); |
| 389 | + var sent = Collections.synchronizedList(new ArrayList<String>()); |
| 390 | + safeGet(sendRequests(targetShards, randomBoolean(), -1, (node, shardIds, aliasFilters, listener) -> { |
| 391 | + sent.add(node.getId()); |
| 392 | + runWithDelay(() -> listener.onResponse(new DataNodeComputeResponse(List.of(), Map.of()))); |
| 393 | + })); |
| 394 | + assertThat(sent, equalTo(List.of("node-1", "node-2", "node-3", "node-4"))); |
| 395 | + } |
| 396 | + |
| 397 | + public void testQueryHotShardsFirstWhenIlmMovesShard() { |
| 398 | + var warmNode2 = DiscoveryNodeUtils.builder("node-2").roles(Set.of(DATA_WARM_NODE_ROLE)).build(); |
| 399 | + var targetShards = shuffledList( |
| 400 | + List.of(targetShard(shard1, node1), targetShard(shard2, shuffledList(List.of(node2, warmNode2)).toArray(DiscoveryNode[]::new))) |
| 401 | + ); |
| 402 | + var sent = ConcurrentCollections.<NodeRequest>newQueue(); |
| 403 | + safeGet(sendRequests(targetShards, randomBoolean(), -1, (node, shardIds, aliasFilters, listener) -> { |
| 404 | + sent.add(new NodeRequest(node, shardIds, aliasFilters)); |
| 405 | + runWithDelay(() -> listener.onResponse(new DataNodeComputeResponse(List.of(), Map.of()))); |
| 406 | + })); |
| 407 | + assertThat(groupRequests(sent, 1), equalTo(Map.of(node1, List.of(shard1)))); |
| 408 | + assertThat(groupRequests(sent, 1), anyOf(equalTo(Map.of(node2, List.of(shard2))), equalTo(Map.of(warmNode2, List.of(shard2))))); |
| 409 | + } |
| 410 | + |
374 | 411 | static DataNodeRequestSender.TargetShard targetShard(ShardId shardId, DiscoveryNode... nodes) { |
375 | 412 | return new DataNodeRequestSender.TargetShard(shardId, new ArrayList<>(Arrays.asList(nodes)), null); |
376 | 413 | } |
@@ -399,8 +436,12 @@ PlainActionFuture<ComputeResponse> sendRequests( |
399 | 436 | Sender sender |
400 | 437 | ) { |
401 | 438 | PlainActionFuture<ComputeResponse> future = new PlainActionFuture<>(); |
402 | | - TransportService transportService = mock(TransportService.class); |
403 | | - when(transportService.getThreadPool()).thenReturn(threadPool); |
| 439 | + TransportService transportService = MockTransportService.createNewService( |
| 440 | + Settings.EMPTY, |
| 441 | + VersionInformation.CURRENT, |
| 442 | + TransportVersion.current(), |
| 443 | + threadPool |
| 444 | + ); |
404 | 445 | CancellableTask task = new CancellableTask( |
405 | 446 | randomNonNegativeLong(), |
406 | 447 | "type", |
|
0 commit comments