Skip to content

Commit ad9c5a0

Browse files
Correctly update search status for a nonexistent local index (#115138)
* fix: correctly update search status for a nonexistent local index * Check for cluster existence before updation * Remove unnecessary `println` * Address review comment: add an explanatory code comment * Further clarify code comment
1 parent e951984 commit ad9c5a0

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

server/src/internalClusterTest/java/org/elasticsearch/search/ccs/CrossClusterSearchIT.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,70 @@ public void testNegativeRemoteIndexNameThrows() {
755755
assertNotNull(ee.getCause());
756756
}
757757

758+
public void testClusterDetailsWhenLocalClusterHasNoMatchingIndex() throws Exception {
759+
Map<String, Object> testClusterInfo = setupTwoClusters();
760+
String remoteIndex = (String) testClusterInfo.get("remote.index");
761+
int remoteNumShards = (Integer) testClusterInfo.get("remote.num_shards");
762+
763+
SearchRequest searchRequest = new SearchRequest("nomatch*", REMOTE_CLUSTER + ":" + remoteIndex);
764+
if (randomBoolean()) {
765+
searchRequest = searchRequest.scroll(TimeValue.timeValueMinutes(1));
766+
}
767+
768+
searchRequest.allowPartialSearchResults(false);
769+
if (randomBoolean()) {
770+
searchRequest.setBatchedReduceSize(randomIntBetween(3, 20));
771+
}
772+
773+
boolean minimizeRoundtrips = false;
774+
searchRequest.setCcsMinimizeRoundtrips(minimizeRoundtrips);
775+
776+
boolean dfs = randomBoolean();
777+
if (dfs) {
778+
searchRequest.searchType(SearchType.DFS_QUERY_THEN_FETCH);
779+
}
780+
781+
if (randomBoolean()) {
782+
searchRequest.setPreFilterShardSize(1);
783+
}
784+
785+
searchRequest.source(new SearchSourceBuilder().query(new MatchAllQueryBuilder()).size(10));
786+
assertResponse(client(LOCAL_CLUSTER).search(searchRequest), response -> {
787+
assertNotNull(response);
788+
789+
Clusters clusters = response.getClusters();
790+
assertFalse("search cluster results should BE successful", clusters.hasPartialResults());
791+
assertThat(clusters.getTotal(), equalTo(2));
792+
assertThat(clusters.getClusterStateCount(Cluster.Status.SUCCESSFUL), equalTo(2));
793+
assertThat(clusters.getClusterStateCount(Cluster.Status.SKIPPED), equalTo(0));
794+
assertThat(clusters.getClusterStateCount(Cluster.Status.RUNNING), equalTo(0));
795+
assertThat(clusters.getClusterStateCount(Cluster.Status.PARTIAL), equalTo(0));
796+
assertThat(clusters.getClusterStateCount(Cluster.Status.FAILED), equalTo(0));
797+
798+
Cluster localClusterSearchInfo = clusters.getCluster(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY);
799+
assertNotNull(localClusterSearchInfo);
800+
assertThat(localClusterSearchInfo.getStatus(), equalTo(Cluster.Status.SUCCESSFUL));
801+
assertThat(localClusterSearchInfo.getIndexExpression(), equalTo("nomatch*"));
802+
assertThat(localClusterSearchInfo.getTotalShards(), equalTo(0));
803+
assertThat(localClusterSearchInfo.getSuccessfulShards(), equalTo(0));
804+
assertThat(localClusterSearchInfo.getSkippedShards(), equalTo(0));
805+
assertThat(localClusterSearchInfo.getFailedShards(), equalTo(0));
806+
assertThat(localClusterSearchInfo.getFailures().size(), equalTo(0));
807+
assertThat(localClusterSearchInfo.getTook().millis(), equalTo(0L));
808+
809+
Cluster remoteClusterSearchInfo = clusters.getCluster(REMOTE_CLUSTER);
810+
assertNotNull(remoteClusterSearchInfo);
811+
assertThat(remoteClusterSearchInfo.getStatus(), equalTo(Cluster.Status.SUCCESSFUL));
812+
assertThat(remoteClusterSearchInfo.getIndexExpression(), equalTo(remoteIndex));
813+
assertThat(remoteClusterSearchInfo.getTotalShards(), equalTo(remoteNumShards));
814+
assertThat(remoteClusterSearchInfo.getSuccessfulShards(), equalTo(remoteNumShards));
815+
assertThat(remoteClusterSearchInfo.getSkippedShards(), equalTo(0));
816+
assertThat(remoteClusterSearchInfo.getFailedShards(), equalTo(0));
817+
assertThat(remoteClusterSearchInfo.getFailures().size(), equalTo(0));
818+
assertThat(remoteClusterSearchInfo.getTook().millis(), greaterThan(0L));
819+
});
820+
}
821+
758822
private static void assertOneFailedShard(Cluster cluster, int totalShards) {
759823
assertNotNull(cluster);
760824
assertThat(cluster.getStatus(), equalTo(Cluster.Status.PARTIAL));

server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,29 @@ private void executeSearch(
12471247
indicesAndAliases,
12481248
concreteLocalIndices
12491249
);
1250+
1251+
// localShardIterators is empty since there are no matching indices. In such cases,
1252+
// we update the local cluster's status from RUNNING to SUCCESSFUL right away. Before
1253+
// we attempt to do that, we must ensure that the local cluster was specified in the user's
1254+
// search request. This is done by trying to fetch the local cluster via getCluster() and
1255+
// checking for a non-null return value. If the local cluster was never specified, its status
1256+
// update can be skipped.
1257+
if (localShardIterators.isEmpty()
1258+
&& clusters != SearchResponse.Clusters.EMPTY
1259+
&& clusters.getCluster(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY) != null) {
1260+
clusters.swapCluster(
1261+
RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY,
1262+
(alias, v) -> new SearchResponse.Cluster.Builder(v).setStatus(SearchResponse.Cluster.Status.SUCCESSFUL)
1263+
.setTotalShards(0)
1264+
.setSuccessfulShards(0)
1265+
.setSkippedShards(0)
1266+
.setFailedShards(0)
1267+
.setFailures(Collections.emptyList())
1268+
.setTook(TimeValue.timeValueMillis(0))
1269+
.setTimedOut(false)
1270+
.build()
1271+
);
1272+
}
12501273
}
12511274
final GroupShardsIterator<SearchShardIterator> shardIterators = mergeShardsIterators(localShardIterators, remoteShardIterators);
12521275

0 commit comments

Comments
 (0)