|
12 | 12 | import org.apache.logging.log4j.Logger;
|
13 | 13 | import org.elasticsearch.Version;
|
14 | 14 | import org.elasticsearch.action.ActionListener;
|
| 15 | +import org.elasticsearch.cluster.ClusterName; |
15 | 16 | import org.elasticsearch.cluster.ClusterState;
|
16 | 17 | import org.elasticsearch.cluster.ESAllocationTestCase;
|
17 | 18 | import org.elasticsearch.cluster.TestShardRoutingRoleStrategies;
|
18 | 19 | import org.elasticsearch.cluster.metadata.IndexMetadata;
|
19 | 20 | import org.elasticsearch.cluster.metadata.Metadata;
|
20 | 21 | import org.elasticsearch.cluster.node.DiscoveryNodes;
|
| 22 | +import org.elasticsearch.cluster.routing.AllocationId; |
| 23 | +import org.elasticsearch.cluster.routing.IndexRoutingTable; |
21 | 24 | import org.elasticsearch.cluster.routing.RoutingNodes;
|
22 | 25 | import org.elasticsearch.cluster.routing.RoutingTable;
|
| 26 | +import org.elasticsearch.cluster.routing.ShardRoutingState; |
| 27 | +import org.elasticsearch.cluster.routing.TestShardRouting; |
| 28 | +import org.elasticsearch.cluster.routing.allocation.allocator.DesiredBalanceShardsAllocator; |
23 | 29 | import org.elasticsearch.cluster.routing.allocation.decider.ClusterRebalanceAllocationDecider;
|
| 30 | +import org.elasticsearch.common.UUIDs; |
24 | 31 | import org.elasticsearch.common.settings.Settings;
|
| 32 | +import org.elasticsearch.index.shard.ShardId; |
| 33 | + |
| 34 | +import java.util.Set; |
| 35 | +import java.util.function.IntFunction; |
25 | 36 |
|
26 | 37 | import static org.elasticsearch.cluster.routing.ShardRoutingState.INITIALIZING;
|
27 | 38 | import static org.elasticsearch.cluster.routing.ShardRoutingState.STARTED;
|
@@ -440,4 +451,76 @@ public void testBalanceAllNodesStartedAddIndex() {
|
440 | 451 | assertThat(routingNodes.node("node2").shardsWithState("test1", STARTED).count(), equalTo(2L));
|
441 | 452 | assertThat(routingNodes.node("node3").shardsWithState("test1", STARTED).count(), equalTo(2L));
|
442 | 453 | }
|
| 454 | + |
| 455 | + /** |
| 456 | + * {@see https://github.com/elastic/elasticsearch/issues/87279} |
| 457 | + */ |
| 458 | + public void testRebalance() { |
| 459 | + final var settings = Settings.builder() |
| 460 | + .put("cluster.routing.allocation.cluster_concurrent_rebalance", randomIntBetween(3, 9)) |
| 461 | + .build(); |
| 462 | + final var allocationService = createAllocationService(settings); |
| 463 | + assumeTrue("", allocationService.shardsAllocator instanceof DesiredBalanceShardsAllocator); |
| 464 | + |
| 465 | + final var discoveryNodesBuilder = DiscoveryNodes.builder(); |
| 466 | + for (int nodeIndex = 0; nodeIndex < 3; nodeIndex++) { |
| 467 | + discoveryNodesBuilder.add(newNode("node-" + nodeIndex)); |
| 468 | + } |
| 469 | + |
| 470 | + final var metadataBuilder = Metadata.builder(); |
| 471 | + final var routingTableBuilder = RoutingTable.builder(); |
| 472 | + |
| 473 | + addIndex(metadataBuilder, routingTableBuilder, "index-0", 4, shardId -> "node-" + (shardId / 2)); |
| 474 | + addIndex(metadataBuilder, routingTableBuilder, "index-1", 4, shardId -> "node-" + (shardId / 2)); |
| 475 | + addIndex(metadataBuilder, routingTableBuilder, "index-2", 1, shardId -> "node-2"); |
| 476 | + |
| 477 | + final var clusterState = ClusterState.builder(ClusterName.DEFAULT) |
| 478 | + .nodes(discoveryNodesBuilder) |
| 479 | + .metadata(metadataBuilder) |
| 480 | + .routingTable(routingTableBuilder) |
| 481 | + .build(); |
| 482 | + |
| 483 | + final var reroutedState = applyStartedShardsUntilNoChange(clusterState, allocationService); |
| 484 | + // node-0 and node-1 has 4 shards each. node-2 has only [index-2][0]. It should not be moved to achieve even balance. |
| 485 | + assertThat(reroutedState.getRoutingTable().index("index-2").shard(0).primaryShard().currentNodeId(), equalTo("node-2")); |
| 486 | + } |
| 487 | + |
| 488 | + private static void addIndex( |
| 489 | + Metadata.Builder metadataBuilder, |
| 490 | + RoutingTable.Builder routingTableBuilder, |
| 491 | + String indexName, |
| 492 | + int numberOfShards, |
| 493 | + IntFunction<String> assignmentFunction |
| 494 | + ) { |
| 495 | + final var inSyncIds = randomList(numberOfShards, numberOfShards, () -> UUIDs.randomBase64UUID(random())); |
| 496 | + final var indexMetadataBuilder = IndexMetadata.builder(indexName) |
| 497 | + .settings( |
| 498 | + Settings.builder() |
| 499 | + .put("index.number_of_shards", numberOfShards) |
| 500 | + .put("index.number_of_replicas", 0) |
| 501 | + .put("index.version.created", Version.CURRENT) |
| 502 | + .build() |
| 503 | + ); |
| 504 | + for (int shardId = 0; shardId < numberOfShards; shardId++) { |
| 505 | + indexMetadataBuilder.putInSyncAllocationIds(shardId, Set.of(inSyncIds.get(shardId))); |
| 506 | + } |
| 507 | + metadataBuilder.put(indexMetadataBuilder); |
| 508 | + final var indexId = metadataBuilder.get(indexName).getIndex(); |
| 509 | + final var indexRoutingTableBuilder = IndexRoutingTable.builder(indexId); |
| 510 | + |
| 511 | + for (int shardId = 0; shardId < numberOfShards; shardId++) { |
| 512 | + indexRoutingTableBuilder.addShard( |
| 513 | + TestShardRouting.newShardRouting( |
| 514 | + new ShardId(indexId, shardId), |
| 515 | + assignmentFunction.apply(shardId), |
| 516 | + null, |
| 517 | + true, |
| 518 | + ShardRoutingState.STARTED, |
| 519 | + AllocationId.newInitializing(inSyncIds.get(shardId)) |
| 520 | + ) |
| 521 | + ); |
| 522 | + } |
| 523 | + |
| 524 | + routingTableBuilder.add(indexRoutingTableBuilder); |
| 525 | + } |
443 | 526 | }
|
0 commit comments