Skip to content

Commit

Permalink
Prefer primaries in cluster allocation explain (#76220)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DaveCTurner committed Aug 9, 2021
1 parent cee82e9 commit f86929f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,14 @@ public static ClusterAllocationExplanation explainShard(
public static ShardRouting findShardToExplain(ClusterAllocationExplainRequest request, RoutingAllocation allocation) {
ShardRouting foundShard = null;
if (request.useAnyUnassignedShard()) {
// If we can use any shard, just pick the first unassigned one (if there are any)
RoutingNodes.UnassignedShards.UnassignedIterator ui = allocation.routingNodes().unassigned().iterator();
if (ui.hasNext()) {
foundShard = ui.next();
// If we can use any shard, return the first unassigned primary (if there is one) or the first unassigned replica (if not)
for (ShardRouting unassigned : allocation.routingNodes().unassigned()) {
if (foundShard == null || unassigned.primary()) {
foundShard = unassigned;
}
if (foundShard.primary()) {
break;
}
}
if (foundShard == null) {
throw new IllegalArgumentException("No shard was specified in the request which means the response should explain a " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@

import org.elasticsearch.action.support.replication.ClusterStateCreationUtils;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
import org.elasticsearch.cluster.routing.RoutingNode;
import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.ShardRoutingState;
import org.elasticsearch.cluster.routing.UnassignedInfo;
Expand Down Expand Up @@ -114,6 +117,33 @@ public void testFindAnyUnassignedShardToExplain() {
shard = findShardToExplain(request, routingAllocation(clusterState));
assertEquals(clusterState.getRoutingTable().index("idx").shard(0).replicaShards().get(0), shard);

// prefer unassigned primary to replica
clusterState = ClusterStateCreationUtils.stateWithAssignedPrimariesAndReplicas(new String[]{"idx1", "idx2"}, 1, 1);
final String redIndex = randomBoolean() ? "idx1" : "idx2";
final RoutingTable.Builder routingTableBuilder = RoutingTable.builder(clusterState.routingTable());
for (final IndexRoutingTable indexRoutingTable : clusterState.routingTable()) {
final IndexRoutingTable.Builder indexBuilder = new IndexRoutingTable.Builder(indexRoutingTable.getIndex());
for (final IndexShardRoutingTable indexShardRoutingTable : indexRoutingTable) {
final IndexShardRoutingTable.Builder shardBuilder = new IndexShardRoutingTable.Builder(indexShardRoutingTable.shardId());
for (final ShardRouting shardRouting : indexShardRoutingTable) {
if (shardRouting.primary() == false || indexRoutingTable.getIndex().getName().equals(redIndex)) {
// move all replicas and one primary to unassigned
shardBuilder.addShard(shardRouting.moveToUnassigned(new UnassignedInfo(
UnassignedInfo.Reason.ALLOCATION_FAILED,
"test")));
} else {
shardBuilder.addShard(shardRouting);
}
}
indexBuilder.addIndexShard(shardBuilder.build());
}
routingTableBuilder.add(indexBuilder);
}
clusterState = ClusterState.builder(clusterState).routingTable(routingTableBuilder.build()).build();
request = new ClusterAllocationExplainRequest();
shard = findShardToExplain(request, routingAllocation(clusterState));
assertEquals(clusterState.getRoutingTable().index(redIndex).shard(0).primaryShard(), shard);

// no unassigned shard to explain
final ClusterState allStartedClusterState = ClusterStateCreationUtils.state("idx", randomBoolean(),
ShardRoutingState.STARTED, ShardRoutingState.STARTED);
Expand Down

0 comments on commit f86929f

Please sign in to comment.