Browse Source

Speedup OperationRouting#searchShards (#100073)

This got visibly slower due to the stateless path with almost all of the
time being burnt on checking the fast refresh index setting.
I added a fast-path for stateful that skips the setting lookup, making
the method much cheaper again.
Armin Braun 2 years ago
parent
commit
4a9ae2c16a

+ 23 - 7
server/src/main/java/org/elasticsearch/cluster/routing/OperationRouting.java

@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -125,16 +126,32 @@ public class OperationRouting {
                 nodeCounts
             );
             if (iterator != null) {
-                var shardsThatCanHandleSearches = iterator.getShardRoutings()
-                    .stream()
-                    .filter(shardRouting -> canSearchShard(shardRouting, clusterState))
-                    .toList();
+                final List<ShardRouting> shardsThatCanHandleSearches;
+                if (isStateless) {
+                    shardsThatCanHandleSearches = statelessShardsThatHandleSearches(clusterState, iterator);
+                } else {
+                    shardsThatCanHandleSearches = statefulShardsThatHandleSearches(iterator);
+                }
                 set.add(new PlainShardIterator(iterator.shardId(), shardsThatCanHandleSearches));
             }
         }
         return GroupShardsIterator.sortAndCreate(new ArrayList<>(set));
     }
 
+    private static List<ShardRouting> statefulShardsThatHandleSearches(ShardIterator iterator) {
+        final List<ShardRouting> shardsThatCanHandleSearches = new ArrayList<>(iterator.size());
+        for (ShardRouting shardRouting : iterator) {
+            if (shardRouting.isSearchable()) {
+                shardsThatCanHandleSearches.add(shardRouting);
+            }
+        }
+        return shardsThatCanHandleSearches;
+    }
+
+    private static List<ShardRouting> statelessShardsThatHandleSearches(ClusterState clusterState, ShardIterator iterator) {
+        return iterator.getShardRoutings().stream().filter(shardRouting -> canSearchShard(shardRouting, clusterState)).toList();
+    }
+
     public static ShardIterator getShards(ClusterState clusterState, ShardId shardId) {
         final IndexShardRoutingTable shard = clusterState.routingTable().shardRoutingTable(shardId);
         return shard.activeInitializingShardsRandomIt();
@@ -177,7 +194,7 @@ public class OperationRouting {
         @Nullable Map<String, Long> nodeCounts
     ) {
         if (preference == null || preference.isEmpty()) {
-            return shardRoutings(indexShard, nodes, collectorService, nodeCounts);
+            return shardRoutings(indexShard, collectorService, nodeCounts);
         }
         if (preference.charAt(0) == '_') {
             Preference preferenceType = Preference.parse(preference);
@@ -204,7 +221,7 @@ public class OperationRouting {
                 }
                 // no more preference
                 if (index == -1 || index == preference.length() - 1) {
-                    return shardRoutings(indexShard, nodes, collectorService, nodeCounts);
+                    return shardRoutings(indexShard, collectorService, nodeCounts);
                 } else {
                     // update the preference and continue
                     preference = preference.substring(index + 1);
@@ -237,7 +254,6 @@ public class OperationRouting {
 
     private ShardIterator shardRoutings(
         IndexShardRoutingTable indexShard,
-        DiscoveryNodes nodes,
         @Nullable ResponseCollectorService collectorService,
         @Nullable Map<String, Long> nodeCounts
     ) {