2525import org .elasticsearch .action .search .SearchResponse ;
2626import org .elasticsearch .client .Client ;
2727import org .elasticsearch .cluster .health .ClusterHealthStatus ;
28+ import org .elasticsearch .cluster .metadata .IndexMetaData ;
2829import org .elasticsearch .cluster .routing .OperationRouting ;
30+ import org .elasticsearch .cluster .routing .allocation .decider .EnableAllocationDecider ;
2931import org .elasticsearch .common .Strings ;
3032import org .elasticsearch .common .settings .Settings ;
3133import org .elasticsearch .common .xcontent .XContentType ;
34+ import org .elasticsearch .node .Node ;
3235import org .elasticsearch .rest .RestStatus ;
3336import org .elasticsearch .test .ESIntegTestCase ;
3437
4245import static org .elasticsearch .test .hamcrest .ElasticsearchAssertions .assertAcked ;
4346import static org .hamcrest .CoreMatchers .containsString ;
4447import static org .hamcrest .Matchers .equalTo ;
45- import static org .hamcrest .Matchers .hasToString ;
46- import static org .hamcrest .Matchers .not ;
4748import static org .hamcrest .Matchers .greaterThan ;
4849import static org .hamcrest .Matchers .greaterThanOrEqualTo ;
50+ import static org .hamcrest .Matchers .hasToString ;
51+ import static org .hamcrest .Matchers .not ;
4952
5053@ ESIntegTestCase .ClusterScope (minNumDataNodes = 2 )
5154public class SearchPreferenceIT extends ESIntegTestCase {
@@ -57,7 +60,7 @@ public Settings nodeSettings(int nodeOrdinal) {
5760 }
5861
5962 // see #2896
60- public void testStopOneNodePreferenceWithRedState () throws InterruptedException , IOException {
63+ public void testStopOneNodePreferenceWithRedState () throws IOException {
6164 assertAcked (prepareCreate ("test" ).setSettings (Settings .builder ().put ("index.number_of_shards" , cluster ().numDataNodes ()+2 )
6265 .put ("index.number_of_replicas" , 0 )));
6366 ensureGreen ();
@@ -87,7 +90,7 @@ public void testStopOneNodePreferenceWithRedState() throws InterruptedException,
8790 assertThat ("_only_local" , searchResponse .getFailedShards (), greaterThanOrEqualTo (0 ));
8891 }
8992
90- public void testNoPreferenceRandom () throws Exception {
93+ public void testNoPreferenceRandom () {
9194 assertAcked (prepareCreate ("test" ).setSettings (
9295 //this test needs at least a replica to make sure two consecutive searches go to two different copies of the same data
9396 Settings .builder ().put (indexSettings ()).put (SETTING_NUMBER_OF_REPLICAS , between (1 , maximumNumberOfReplicas ()))
@@ -106,7 +109,7 @@ public void testNoPreferenceRandom() throws Exception {
106109 assertThat (firstNodeId , not (equalTo (secondNodeId )));
107110 }
108111
109- public void testSimplePreference () throws Exception {
112+ public void testSimplePreference () {
110113 client ().admin ().indices ().prepareCreate ("test" ).setSettings ("{\" number_of_replicas\" : 1}" , XContentType .JSON ).get ();
111114 ensureGreen ();
112115
@@ -123,7 +126,7 @@ public void testSimplePreference() throws Exception {
123126 assertThat (searchResponse .getHits ().getTotalHits ().value , equalTo (1L ));
124127 }
125128
126- public void testThatSpecifyingNonExistingNodesReturnsUsefulError () throws Exception {
129+ public void testThatSpecifyingNonExistingNodesReturnsUsefulError () {
127130 createIndex ("test" );
128131 ensureGreen ();
129132
@@ -135,7 +138,7 @@ public void testThatSpecifyingNonExistingNodesReturnsUsefulError() throws Except
135138 }
136139 }
137140
138- public void testNodesOnlyRandom () throws Exception {
141+ public void testNodesOnlyRandom () {
139142 assertAcked (prepareCreate ("test" ).setSettings (
140143 //this test needs at least a replica to make sure two consecutive searches go to two different copies of the same data
141144 Settings .builder ().put (indexSettings ()).put (SETTING_NUMBER_OF_REPLICAS , between (1 , maximumNumberOfReplicas ()))));
@@ -193,4 +196,58 @@ private void assertSearchOnRandomNodes(SearchRequestBuilder request) {
193196 }
194197 assertThat (hitNodes .size (), greaterThan (1 ));
195198 }
199+
200+ public void testCustomPreferenceUnaffectedByOtherShardMovements () {
201+
202+ /*
203+ * Custom preferences can be used to encourage searches to go to a consistent set of shard copies, meaning that other copies' data
204+ * is rarely touched and can be dropped from the filesystem cache. This works best if the set of shards searched doesn't change
205+ * unnecessarily, so this test verifies a consistent routing even as other shards are created/relocated/removed.
206+ */
207+
208+ assertAcked (prepareCreate ("test" ).setSettings (Settings .builder ().put (indexSettings ())
209+ .put (SETTING_NUMBER_OF_REPLICAS , between (1 , maximumNumberOfReplicas ()))
210+ .put (EnableAllocationDecider .INDEX_ROUTING_REBALANCE_ENABLE_SETTING .getKey (), EnableAllocationDecider .Rebalance .NONE )));
211+ ensureGreen ();
212+ client ().prepareIndex ("test" , "_doc" ).setSource ("field1" , "value1" ).get ();
213+ refresh ();
214+
215+ final String customPreference = randomAlphaOfLength (10 );
216+
217+ final String nodeId = client ().prepareSearch ("test" ).setQuery (matchAllQuery ()).setPreference (customPreference )
218+ .get ().getHits ().getAt (0 ).getShard ().getNodeId ();
219+
220+ assertSearchesSpecificNode ("test" , customPreference , nodeId );
221+
222+ final int replicasInNewIndex = between (1 , maximumNumberOfReplicas ());
223+ assertAcked (prepareCreate ("test2" ).setSettings (
224+ Settings .builder ().put (indexSettings ()).put (SETTING_NUMBER_OF_REPLICAS , replicasInNewIndex )));
225+ ensureGreen ();
226+
227+ assertSearchesSpecificNode ("test" , customPreference , nodeId );
228+
229+ assertAcked (client ().admin ().indices ().prepareUpdateSettings ("test2" ).setSettings (Settings .builder ()
230+ .put (SETTING_NUMBER_OF_REPLICAS , replicasInNewIndex - 1 )));
231+
232+ assertSearchesSpecificNode ("test" , customPreference , nodeId );
233+
234+ assertAcked (client ().admin ().indices ().prepareUpdateSettings ("test2" ).setSettings (Settings .builder ()
235+ .put (SETTING_NUMBER_OF_REPLICAS , 0 )
236+ .put (IndexMetaData .INDEX_ROUTING_REQUIRE_GROUP_PREFIX + "._name" ,
237+ internalCluster ().getDataNodeInstance (Node .class ).settings ().get (Node .NODE_NAME_SETTING .getKey ()))));
238+
239+ ensureGreen ();
240+
241+ assertSearchesSpecificNode ("test" , customPreference , nodeId );
242+
243+ assertAcked (client ().admin ().indices ().prepareDelete ("test2" ));
244+
245+ assertSearchesSpecificNode ("test" , customPreference , nodeId );
246+ }
247+
248+ private static void assertSearchesSpecificNode (String index , String customPreference , String nodeId ) {
249+ final SearchResponse searchResponse = client ().prepareSearch (index ).setQuery (matchAllQuery ()).setPreference (customPreference ).get ();
250+ assertThat (searchResponse .getHits ().getHits ().length , equalTo (1 ));
251+ assertThat (searchResponse .getHits ().getAt (0 ).getShard ().getNodeId (), equalTo (nodeId ));
252+ }
196253}
0 commit comments