5454import java .util .Map ;
5555import java .util .Set ;
5656import java .util .function .BiFunction ;
57- import java .util .stream .StreamSupport ;
5857
5958import static org .elasticsearch .cluster .metadata .SingleNodeShutdownMetadata .Type .REPLACE ;
6059import static org .elasticsearch .cluster .routing .ExpectedShardSizeEstimator .getExpectedShardSize ;
@@ -1091,7 +1090,13 @@ private AllocateUnassignedDecision decideAllocateUnassigned(final ProjectIndex i
10911090 return AllocateUnassignedDecision .fromDecision (decision , minNode != null ? minNode .routingNode .node () : null , nodeDecisions );
10921091 }
10931092
1094- private static final Comparator <ShardRouting > BY_DESCENDING_SHARD_ID = Comparator .comparing (ShardRouting ::shardId ).reversed ();
1093+ private static final Comparator <ShardRouting > BY_DESCENDING_SHARD_ID = (s1 , s2 ) -> Integer .compare (s2 .id (), s1 .id ());
1094+
1095+ /**
1096+ * Scratch space for accumulating/sorting the {@link ShardRouting} instances when contemplating moving the shards away from a node
1097+ * in {@link #tryRelocateShard} - re-used to avoid extraneous allocations etc.
1098+ */
1099+ private ShardRouting [] shardRoutingsOnMaxWeightNode ;
10951100
10961101 /**
10971102 * Tries to find a relocation from the max node to the minimal node for an arbitrary shard of the given index on the
@@ -1102,13 +1107,24 @@ private boolean tryRelocateShard(ModelNode minNode, ModelNode maxNode, ProjectIn
11021107 final ModelIndex index = maxNode .getIndex (idx );
11031108 if (index != null ) {
11041109 logger .trace ("Try relocating shard of [{}] from [{}] to [{}]" , idx , maxNode .getNodeId (), minNode .getNodeId ());
1105- final Iterable <ShardRouting > shardRoutings = StreamSupport .stream (index .spliterator (), false )
1106- .filter (ShardRouting ::started ) // cannot rebalance unassigned, initializing or relocating shards anyway
1107- .sorted (BY_DESCENDING_SHARD_ID ) // check in descending order of shard id so that the decision is deterministic
1108- ::iterator ;
1110+ if (shardRoutingsOnMaxWeightNode == null || shardRoutingsOnMaxWeightNode .length < index .numShards ()) {
1111+ shardRoutingsOnMaxWeightNode = new ShardRouting [index .numShards () * 2 ]; // oversized so reuse is more likely
1112+ }
1113+
1114+ int startedShards = 0 ;
1115+ for (final var shardRouting : index ) {
1116+ if (shardRouting .started ()) { // cannot rebalance unassigned, initializing or relocating shards anyway
1117+ shardRoutingsOnMaxWeightNode [startedShards ] = shardRouting ;
1118+ startedShards += 1 ;
1119+ }
1120+ }
1121+ // check in descending order of shard id so that the decision is deterministic
1122+ ArrayUtil .timSort (shardRoutingsOnMaxWeightNode , 0 , startedShards , BY_DESCENDING_SHARD_ID );
11091123
11101124 final AllocationDeciders deciders = allocation .deciders ();
1111- for (ShardRouting shard : shardRoutings ) {
1125+ for (int shardIndex = 0 ; shardIndex < startedShards ; shardIndex ++) {
1126+ final ShardRouting shard = shardRoutingsOnMaxWeightNode [shardIndex ];
1127+
11121128 final Decision rebalanceDecision = deciders .canRebalance (shard , allocation );
11131129 if (rebalanceDecision .type () == Type .NO ) {
11141130 continue ;
0 commit comments