Skip to content

Commit d0bd895

Browse files
committed
Searching while an index is being allocated and no active shards exists within a "shard replication group" can cause search "misses", closes elastic#736.
1 parent d5dce70 commit d0bd895

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

modules/elasticsearch/src/main/java/org/elasticsearch/action/search/type/TransportSearchTypeAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ protected BaseAsyncAction(SearchRequest request, ActionListener<SearchResponse>
112112

113113
shardsIts = clusterService.operationRouting().searchShards(clusterState, request.indices(), request.queryHint(), request.routing());
114114
expectedSuccessfulOps = shardsIts.size();
115-
expectedTotalOps = shardsIts.totalSizeActive();
115+
// we need to add 1 for non active partition, since we count it in the total!
116+
expectedTotalOps = shardsIts.totalSizeActiveWith1ForEmpty();
116117

117118
if (expectedSuccessfulOps == 0) {
118119
// not search shards to search on...

modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/GroupShardsIterator.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ public int totalSize() {
4141
return size;
4242
}
4343

44+
public int totalSizeActiveWith1ForEmpty() {
45+
int size = 0;
46+
for (ShardIterator shard : iterators) {
47+
int sizeActive = shard.sizeActive();
48+
if (sizeActive == 0) {
49+
size += 1;
50+
} else {
51+
size += sizeActive;
52+
}
53+
}
54+
return size;
55+
}
56+
4457
public int totalSizeActive() {
4558
int size = 0;
4659
for (ShardIterator shard : iterators) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Licensed to Elastic Search and Shay Banon under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. Elastic Search licenses this
6+
* file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.test.integration.search.basic;
21+
22+
import org.elasticsearch.action.search.SearchResponse;
23+
import org.elasticsearch.index.query.xcontent.QueryBuilders;
24+
import org.elasticsearch.node.Node;
25+
import org.elasticsearch.test.integration.AbstractNodesTests;
26+
import org.testng.annotations.AfterMethod;
27+
import org.testng.annotations.Test;
28+
29+
import static org.elasticsearch.common.settings.ImmutableSettings.*;
30+
import static org.hamcrest.MatcherAssert.*;
31+
import static org.hamcrest.Matchers.*;
32+
33+
public class SearchWhileCreatingIndexTests extends AbstractNodesTests {
34+
35+
@AfterMethod public void closeAll() {
36+
closeAllNodes();
37+
}
38+
39+
/**
40+
* This test basically verifies that search with a single shard active (cause we indexed to it) and other
41+
* shards possibly not active at all (cause they haven't allocated) will still work.
42+
*/
43+
@Test public void searchWhileCreatingIndex() {
44+
Node node = startNode("node1");
45+
46+
try {
47+
node.client().admin().indices().prepareDelete("test").execute().actionGet();
48+
} catch (Exception e) {
49+
// ignore
50+
}
51+
52+
for (int i = 0; i < 20; i++) {
53+
node.client().admin().indices().prepareCreate("test").setSettings(settingsBuilder().put("number_of_shards", 10)).execute().actionGet();
54+
55+
node.client().prepareIndex("test", "type1").setSource("field", "test").execute().actionGet();
56+
node.client().admin().indices().prepareRefresh().execute().actionGet();
57+
58+
SearchResponse searchResponse = node.client().prepareSearch("test").setQuery(QueryBuilders.termQuery("field", "test")).execute().actionGet();
59+
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
60+
61+
node.client().admin().indices().prepareDelete("test").execute().actionGet();
62+
}
63+
64+
try {
65+
node.client().admin().indices().prepareDelete("test").execute().actionGet();
66+
} catch (Exception e) {
67+
// ignore
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)