Skip to content

Commit a910a1b

Browse files
authored
Remove nested loop in IndicesStatsResponse (#40988) (#41139)
This commit removes nested loop in `getIndices`.
1 parent 639f4f3 commit a910a1b

File tree

3 files changed

+99
-20
lines changed

3 files changed

+99
-20
lines changed

server/src/main/java/org/elasticsearch/action/admin/indices/stats/IndexStats.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,24 @@ public CommonStats getPrimaries() {
108108
primary = stats;
109109
return stats;
110110
}
111+
112+
public static class IndexStatsBuilder {
113+
private final String indexName;
114+
private final String uuid;
115+
private final List<ShardStats> shards = new ArrayList<>();
116+
117+
public IndexStatsBuilder(String indexName, String uuid) {
118+
this.indexName = indexName;
119+
this.uuid = uuid;
120+
}
121+
122+
public IndexStatsBuilder add(ShardStats shardStats) {
123+
shards.add(shardStats);
124+
return this;
125+
}
126+
127+
public IndexStats build() {
128+
return new IndexStats(indexName, uuid, shards.toArray(new ShardStats[shards.size()]));
129+
}
130+
}
111131
}

server/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.action.admin.indices.stats;
2121

22+
import org.elasticsearch.action.admin.indices.stats.IndexStats.IndexStatsBuilder;
2223
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
2324
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
2425
import org.elasticsearch.cluster.routing.ShardRouting;
@@ -29,12 +30,10 @@
2930
import org.elasticsearch.index.Index;
3031

3132
import java.io.IOException;
32-
import java.util.ArrayList;
3333
import java.util.HashMap;
34-
import java.util.HashSet;
3534
import java.util.List;
3635
import java.util.Map;
37-
import java.util.Set;
36+
import java.util.stream.Collectors;
3837

3938
import static java.util.Collections.unmodifiableMap;
4039

@@ -83,26 +82,17 @@ public Map<String, IndexStats> getIndices() {
8382
if (indicesStats != null) {
8483
return indicesStats;
8584
}
86-
Map<String, IndexStats> indicesStats = new HashMap<>();
8785

88-
Set<Index> indices = new HashSet<>();
86+
final Map<String, IndexStatsBuilder> indexToIndexStatsBuilder = new HashMap<>();
8987
for (ShardStats shard : shards) {
90-
indices.add(shard.getShardRouting().index());
88+
Index index = shard.getShardRouting().index();
89+
IndexStatsBuilder indexStatsBuilder = indexToIndexStatsBuilder.computeIfAbsent(index.getName(),
90+
k -> new IndexStatsBuilder(k, index.getUUID()));
91+
indexStatsBuilder.add(shard);
9192
}
9293

93-
for (Index index : indices) {
94-
List<ShardStats> shards = new ArrayList<>();
95-
String indexName = index.getName();
96-
for (ShardStats shard : this.shards) {
97-
if (shard.getShardRouting().getIndexName().equals(indexName)) {
98-
shards.add(shard);
99-
}
100-
}
101-
indicesStats.put(
102-
indexName, new IndexStats(indexName, index.getUUID(), shards.toArray(new ShardStats[shards.size()]))
103-
);
104-
}
105-
this.indicesStats = indicesStats;
94+
indicesStats = indexToIndexStatsBuilder.entrySet().stream()
95+
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().build()));
10696
return indicesStats;
10797
}
10898

server/src/test/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponseTests.java

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,30 @@
1919

2020
package org.elasticsearch.action.admin.indices.stats;
2121

22+
import org.elasticsearch.cluster.routing.ShardRouting;
23+
import org.elasticsearch.cluster.routing.ShardRoutingState;
24+
import org.elasticsearch.cluster.routing.TestShardRouting;
25+
import org.elasticsearch.common.UUIDs;
2226
import org.elasticsearch.common.xcontent.ToXContent;
2327
import org.elasticsearch.common.xcontent.json.JsonXContent;
28+
import org.elasticsearch.index.Index;
29+
import org.elasticsearch.index.shard.ShardId;
30+
import org.elasticsearch.index.shard.ShardPath;
2431
import org.elasticsearch.test.ESTestCase;
2532

33+
import java.nio.file.Path;
34+
import java.util.ArrayList;
2635
import java.util.Collections;
36+
import java.util.HashMap;
37+
import java.util.List;
38+
import java.util.Map;
39+
import java.util.concurrent.atomic.AtomicLong;
2740

2841
import static org.hamcrest.CoreMatchers.containsString;
42+
import static org.hamcrest.Matchers.containsInAnyOrder;
43+
import static org.hamcrest.Matchers.is;
2944
import static org.hamcrest.object.HasToString.hasToString;
3045

31-
3246
public class IndicesStatsResponseTests extends ESTestCase {
3347

3448
public void testInvalidLevel() {
@@ -42,4 +56,59 @@ public void testInvalidLevel() {
4256
hasToString(containsString("level parameter must be one of [cluster] or [indices] or [shards] but was [" + level + "]")));
4357
}
4458

59+
public void testGetIndices() {
60+
List<ShardStats> shards = new ArrayList<>();
61+
int noOfIndexes = randomIntBetween(2, 5);
62+
List<String> expectedIndexes = new ArrayList<>();
63+
Map<String, AtomicLong> expectedIndexToPrimaryShardsCount = new HashMap<>();
64+
Map<String, AtomicLong> expectedIndexToTotalShardsCount = new HashMap<>();
65+
66+
for (int indCnt = 0; indCnt < noOfIndexes; indCnt++) {
67+
Index index = createIndex(randomAlphaOfLength(9));
68+
expectedIndexes.add(index.getName());
69+
int numShards = randomIntBetween(1, 5);
70+
for (int shardId = 0; shardId < numShards; shardId++) {
71+
ShardId shId = new ShardId(index, shardId);
72+
Path path = createTempDir().resolve("indices").resolve(index.getUUID()).resolve(String.valueOf(shardId));
73+
ShardPath shardPath = new ShardPath(false, path, path, shId);
74+
ShardRouting routing = createShardRouting(index, shId, (shardId == 0));
75+
shards.add(new ShardStats(routing, shardPath, null, null, null, null));
76+
AtomicLong primaryShardsCounter = expectedIndexToPrimaryShardsCount.computeIfAbsent(index.getName(),
77+
k -> new AtomicLong(0L));
78+
if (routing.primary()) {
79+
primaryShardsCounter.incrementAndGet();
80+
}
81+
AtomicLong shardsCounter = expectedIndexToTotalShardsCount.computeIfAbsent(index.getName(), k -> new AtomicLong(0L));
82+
shardsCounter.incrementAndGet();
83+
}
84+
}
85+
final IndicesStatsResponse indicesStatsResponse = new IndicesStatsResponse(shards.toArray(new ShardStats[shards.size()]), 0, 0, 0,
86+
null);
87+
Map<String, IndexStats> indexStats = indicesStatsResponse.getIndices();
88+
89+
assertThat(indexStats.size(), is(noOfIndexes));
90+
assertThat(indexStats.keySet(), containsInAnyOrder(expectedIndexes.toArray(new String[0])));
91+
92+
for (String index : indexStats.keySet()) {
93+
IndexStats stat = indexStats.get(index);
94+
ShardStats[] shardStats = stat.getShards();
95+
long primaryCount = 0L;
96+
long totalCount = shardStats.length;
97+
for (ShardStats shardStat : shardStats) {
98+
if (shardStat.getShardRouting().primary()) {
99+
primaryCount++;
100+
}
101+
}
102+
assertThat(primaryCount, is(expectedIndexToPrimaryShardsCount.get(index).get()));
103+
assertThat(totalCount, is(expectedIndexToTotalShardsCount.get(index).get()));
104+
}
105+
}
106+
107+
private ShardRouting createShardRouting(Index index, ShardId shardId, boolean isPrimary) {
108+
return TestShardRouting.newShardRouting(shardId, randomAlphaOfLength(4), isPrimary, ShardRoutingState.STARTED);
109+
}
110+
111+
private Index createIndex(String indexName) {
112+
return new Index(indexName, UUIDs.base64UUID());
113+
}
45114
}

0 commit comments

Comments
 (0)