Skip to content

Commit f86929f

Browse files
committed
Prefer primaries in cluster allocation explain (#76220)
Today by default we explain the first unassigned shard in the routing table. It's not unusual for this to be a replica which is unassigned because its primary is also unassigned, which is not a helpful choice. With this commit we explain the first unassigned primary if one exists, falling back to the first unassigned replica if all primaries are assigned.
1 parent cee82e9 commit f86929f

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

server/src/main/java/org/elasticsearch/action/admin/cluster/allocation/TransportClusterAllocationExplainAction.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,14 @@ public static ClusterAllocationExplanation explainShard(
121121
public static ShardRouting findShardToExplain(ClusterAllocationExplainRequest request, RoutingAllocation allocation) {
122122
ShardRouting foundShard = null;
123123
if (request.useAnyUnassignedShard()) {
124-
// If we can use any shard, just pick the first unassigned one (if there are any)
125-
RoutingNodes.UnassignedShards.UnassignedIterator ui = allocation.routingNodes().unassigned().iterator();
126-
if (ui.hasNext()) {
127-
foundShard = ui.next();
124+
// If we can use any shard, return the first unassigned primary (if there is one) or the first unassigned replica (if not)
125+
for (ShardRouting unassigned : allocation.routingNodes().unassigned()) {
126+
if (foundShard == null || unassigned.primary()) {
127+
foundShard = unassigned;
128+
}
129+
if (foundShard.primary()) {
130+
break;
131+
}
128132
}
129133
if (foundShard == null) {
130134
throw new IllegalArgumentException("No shard was specified in the request which means the response should explain a " +

server/src/test/java/org/elasticsearch/action/admin/cluster/allocation/ClusterAllocationExplainActionTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
import org.elasticsearch.action.support.replication.ClusterStateCreationUtils;
1212
import org.elasticsearch.cluster.ClusterState;
13+
import org.elasticsearch.cluster.routing.IndexRoutingTable;
14+
import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
1315
import org.elasticsearch.cluster.routing.RoutingNode;
16+
import org.elasticsearch.cluster.routing.RoutingTable;
1417
import org.elasticsearch.cluster.routing.ShardRouting;
1518
import org.elasticsearch.cluster.routing.ShardRoutingState;
1619
import org.elasticsearch.cluster.routing.UnassignedInfo;
@@ -114,6 +117,33 @@ public void testFindAnyUnassignedShardToExplain() {
114117
shard = findShardToExplain(request, routingAllocation(clusterState));
115118
assertEquals(clusterState.getRoutingTable().index("idx").shard(0).replicaShards().get(0), shard);
116119

120+
// prefer unassigned primary to replica
121+
clusterState = ClusterStateCreationUtils.stateWithAssignedPrimariesAndReplicas(new String[]{"idx1", "idx2"}, 1, 1);
122+
final String redIndex = randomBoolean() ? "idx1" : "idx2";
123+
final RoutingTable.Builder routingTableBuilder = RoutingTable.builder(clusterState.routingTable());
124+
for (final IndexRoutingTable indexRoutingTable : clusterState.routingTable()) {
125+
final IndexRoutingTable.Builder indexBuilder = new IndexRoutingTable.Builder(indexRoutingTable.getIndex());
126+
for (final IndexShardRoutingTable indexShardRoutingTable : indexRoutingTable) {
127+
final IndexShardRoutingTable.Builder shardBuilder = new IndexShardRoutingTable.Builder(indexShardRoutingTable.shardId());
128+
for (final ShardRouting shardRouting : indexShardRoutingTable) {
129+
if (shardRouting.primary() == false || indexRoutingTable.getIndex().getName().equals(redIndex)) {
130+
// move all replicas and one primary to unassigned
131+
shardBuilder.addShard(shardRouting.moveToUnassigned(new UnassignedInfo(
132+
UnassignedInfo.Reason.ALLOCATION_FAILED,
133+
"test")));
134+
} else {
135+
shardBuilder.addShard(shardRouting);
136+
}
137+
}
138+
indexBuilder.addIndexShard(shardBuilder.build());
139+
}
140+
routingTableBuilder.add(indexBuilder);
141+
}
142+
clusterState = ClusterState.builder(clusterState).routingTable(routingTableBuilder.build()).build();
143+
request = new ClusterAllocationExplainRequest();
144+
shard = findShardToExplain(request, routingAllocation(clusterState));
145+
assertEquals(clusterState.getRoutingTable().index(redIndex).shard(0).primaryShard(), shard);
146+
117147
// no unassigned shard to explain
118148
final ClusterState allStartedClusterState = ClusterStateCreationUtils.state("idx", randomBoolean(),
119149
ShardRoutingState.STARTED, ShardRoutingState.STARTED);

0 commit comments

Comments
 (0)