Skip to content

Commit e13b5d8

Browse files
committed
Merge branch 'master' into get-aliases-not-found
* master: Add support for clear scroll to high level REST client (elastic#25038) Tiny correction in inner-hits.asciidoc (elastic#25066) Added release notes for 6.0.0-alpha2 Expand index expressions against indices only when managing aliases (elastic#23997) Collapse inner hits rest test should not skip 5.x Settings: Fix secure settings by prefix (elastic#25064) add `exclude_keys` option to KeyValueProcessor (elastic#24876) Test: update missing body tests to run against versions >= 5.5.0 Track EWMA[1] of task execution time in search threadpool executor Removes an invalid assert in resizing big arrays which does not always hold (resizing can result in a smaller size than the current size, while the assert attempted to verify the new size is always greater than the current). Fixed NPEs caused by requests without content. (elastic#23497) Plugins can register pre-configured char filters (elastic#25000) Build: Allow preserving shared dir (elastic#24962) Tests: Make secure settings available from settings builder for tests (elastic#25037)
2 parents 0e6d1f7 + d47d479 commit e13b5d8

File tree

76 files changed

+1569
-386
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1569
-386
lines changed

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ class ClusterConfiguration {
7676
" " + "-Xmx" + System.getProperty('tests.heap.size', '512m') +
7777
" " + System.getProperty('tests.jvm.argline', '')
7878

79+
/**
80+
* Should the shared environment be cleaned on cluster startup? Defaults
81+
* to {@code true} so we run with a clean cluster but some tests wish to
82+
* preserve snapshots between clusters so they set this to true.
83+
*/
84+
@Input
85+
boolean cleanShared = true
86+
7987
/**
8088
* A closure to call which returns the unicast host to connect to for cluster formation.
8189
*

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,24 @@ class ClusterFormationTasks {
5454
*/
5555
static List<NodeInfo> setup(Project project, String prefix, Task runner, ClusterConfiguration config) {
5656
File sharedDir = new File(project.buildDir, "cluster/shared")
57-
// first we remove everything in the shared cluster directory to ensure there are no leftovers in repos or anything
58-
// in theory this should not be necessary but repositories are only deleted in the cluster-state and not on-disk
59-
// such that snapshots survive failures / test runs and there is no simple way today to fix that.
60-
Task cleanup = project.tasks.create(name: "${prefix}#prepareCluster.cleanShared", type: Delete, dependsOn: config.dependencies) {
61-
delete sharedDir
62-
doLast {
63-
sharedDir.mkdirs()
64-
}
57+
Object startDependencies = config.dependencies
58+
/* First, if we want a clean environment, we remove everything in the
59+
* shared cluster directory to ensure there are no leftovers in repos
60+
* or anything in theory this should not be necessary but repositories
61+
* are only deleted in the cluster-state and not on-disk such that
62+
* snapshots survive failures / test runs and there is no simple way
63+
* today to fix that. */
64+
if (config.cleanShared) {
65+
Task cleanup = project.tasks.create(
66+
name: "${prefix}#prepareCluster.cleanShared",
67+
type: Delete,
68+
dependsOn: startDependencies) {
69+
delete sharedDir
70+
doLast {
71+
sharedDir.mkdirs()
72+
}
73+
}
74+
startDependencies = cleanup
6575
}
6676
List<Task> startTasks = []
6777
List<NodeInfo> nodes = []
@@ -103,7 +113,7 @@ class ClusterFormationTasks {
103113
}
104114
NodeInfo node = new NodeInfo(config, i, project, prefix, elasticsearchVersion, sharedDir)
105115
nodes.add(node)
106-
Task dependsOn = startTasks.empty ? cleanup : startTasks.get(0)
116+
Object dependsOn = startTasks.empty ? startDependencies : startTasks.get(0)
107117
startTasks.add(configureNode(project, prefix, runner, dependsOn, node, config, distro, nodes.get(0)))
108118
}
109119

client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/bulk/RestNoopBulkAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
7878
}
7979
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
8080
bulkRequest.setRefreshPolicy(request.param("refresh"));
81-
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields, null, defaultPipeline, null, true,
82-
request.getXContentType());
81+
bulkRequest.add(request.requiredContent(), defaultIndex, defaultType, defaultRouting, defaultFields,
82+
null, defaultPipeline, null, true, request.getXContentType());
8383

8484
// short circuit the call to the transport layer
8585
return channel -> {

client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.elasticsearch.action.delete.DeleteRequest;
3434
import org.elasticsearch.action.get.GetRequest;
3535
import org.elasticsearch.action.index.IndexRequest;
36+
import org.elasticsearch.action.search.ClearScrollRequest;
3637
import org.elasticsearch.action.search.SearchRequest;
3738
import org.elasticsearch.action.search.SearchScrollRequest;
3839
import org.elasticsearch.action.support.ActiveShardCount;
@@ -344,6 +345,11 @@ static Request searchScroll(SearchScrollRequest searchScrollRequest) throws IOEx
344345
return new Request("GET", "/_search/scroll", Collections.emptyMap(), entity);
345346
}
346347

348+
static Request clearScroll(ClearScrollRequest clearScrollRequest) throws IOException {
349+
HttpEntity entity = createEntity(clearScrollRequest, REQUEST_BODY_CONTENT_TYPE);
350+
return new Request("DELETE", "/_search/scroll", Collections.emptyMap(), entity);
351+
}
352+
347353
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
348354
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
349355
return new ByteArrayEntity(source.bytes, source.offset, source.length, ContentType.create(xContentType.mediaType()));

client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import org.elasticsearch.action.index.IndexResponse;
3737
import org.elasticsearch.action.main.MainRequest;
3838
import org.elasticsearch.action.main.MainResponse;
39+
import org.elasticsearch.action.search.ClearScrollRequest;
40+
import org.elasticsearch.action.search.ClearScrollResponse;
3941
import org.elasticsearch.action.search.SearchRequest;
4042
import org.elasticsearch.action.search.SearchResponse;
4143
import org.elasticsearch.action.search.SearchScrollRequest;
@@ -347,6 +349,28 @@ public void searchScrollAsync(SearchScrollRequest searchScrollRequest, ActionLis
347349
listener, emptySet(), headers);
348350
}
349351

352+
/**
353+
* Clears one or more scroll ids using the Clear Scroll api
354+
*
355+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html#_clear_scroll_api">
356+
* Clear Scroll API on elastic.co</a>
357+
*/
358+
public ClearScrollResponse clearScroll(ClearScrollRequest clearScrollRequest, Header... headers) throws IOException {
359+
return performRequestAndParseEntity(clearScrollRequest, Request::clearScroll, ClearScrollResponse::fromXContent,
360+
emptySet(), headers);
361+
}
362+
363+
/**
364+
* Asynchronously clears one or more scroll ids using the Clear Scroll api
365+
*
366+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html#_clear_scroll_api">
367+
* Clear Scroll API on elastic.co</a>
368+
*/
369+
public void clearScrollAsync(ClearScrollRequest clearScrollRequest, ActionListener<ClearScrollResponse> listener, Header... headers) {
370+
performRequestAsyncAndParseEntity(clearScrollRequest, Request::clearScroll, ClearScrollResponse::fromXContent,
371+
listener, emptySet(), headers);
372+
}
373+
350374
private <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
351375
CheckedFunction<Req, Request, IOException> requestConverter,
352376
CheckedFunction<XContentParser, Resp, IOException> entityParser,

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.action.delete.DeleteRequest;
2929
import org.elasticsearch.action.get.GetRequest;
3030
import org.elasticsearch.action.index.IndexRequest;
31+
import org.elasticsearch.action.search.ClearScrollRequest;
3132
import org.elasticsearch.action.search.SearchRequest;
3233
import org.elasticsearch.action.search.SearchScrollRequest;
3334
import org.elasticsearch.action.search.SearchType;
@@ -731,6 +732,21 @@ public void testSearchScroll() throws IOException {
731732
assertEquals("/_search/scroll", request.endpoint);
732733
assertEquals(0, request.params.size());
733734
assertToXContentBody(searchScrollRequest, request.entity);
735+
assertEquals(Request.REQUEST_BODY_CONTENT_TYPE.mediaType(), request.entity.getContentType().getValue());
736+
}
737+
738+
public void testClearScroll() throws IOException {
739+
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
740+
int numScrolls = randomIntBetween(1, 10);
741+
for (int i = 0; i < numScrolls; i++) {
742+
clearScrollRequest.addScrollId(randomAlphaOfLengthBetween(5, 10));
743+
}
744+
Request request = Request.clearScroll(clearScrollRequest);
745+
assertEquals("DELETE", request.method);
746+
assertEquals("/_search/scroll", request.endpoint);
747+
assertEquals(0, request.params.size());
748+
assertToXContentBody(clearScrollRequest, request.entity);
749+
assertEquals(Request.REQUEST_BODY_CONTENT_TYPE.mediaType(), request.entity.getContentType().getValue());
734750
}
735751

736752
private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {

client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import org.elasticsearch.action.ActionRequestValidationException;
4343
import org.elasticsearch.action.main.MainRequest;
4444
import org.elasticsearch.action.main.MainResponse;
45+
import org.elasticsearch.action.search.ClearScrollRequest;
46+
import org.elasticsearch.action.search.ClearScrollResponse;
4547
import org.elasticsearch.action.search.SearchResponse;
4648
import org.elasticsearch.action.search.SearchResponseSections;
4749
import org.elasticsearch.action.search.SearchScrollRequest;
@@ -161,6 +163,19 @@ public void testSearchScroll() throws IOException {
161163
isNotNull(HttpEntity.class), argThat(new HeadersVarargMatcher(headers)));
162164
}
163165

166+
public void testClearScroll() throws IOException {
167+
Header[] headers = randomHeaders(random(), "Header");
168+
ClearScrollResponse mockClearScrollResponse = new ClearScrollResponse(randomBoolean(), randomIntBetween(0, Integer.MAX_VALUE));
169+
mockResponse(mockClearScrollResponse);
170+
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
171+
clearScrollRequest.addScrollId(randomAlphaOfLengthBetween(5, 10));
172+
ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, headers);
173+
assertEquals(mockClearScrollResponse.isSucceeded(), clearScrollResponse.isSucceeded());
174+
assertEquals(mockClearScrollResponse.getNumFreed(), clearScrollResponse.getNumFreed());
175+
verify(restClient).performRequest(eq("DELETE"), eq("/_search/scroll"), eq(Collections.emptyMap()),
176+
isNotNull(HttpEntity.class), argThat(new HeadersVarargMatcher(headers)));
177+
}
178+
164179
private void mockResponse(ToXContent toXContent) throws IOException {
165180
Response response = mock(Response.class);
166181
ContentType contentType = ContentType.parse(Request.REQUEST_BODY_CONTENT_TYPE.mediaType());

client/rest-high-level/src/test/java/org/elasticsearch/client/SearchIT.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@
1919

2020
package org.elasticsearch.client;
2121

22+
import org.apache.http.HttpEntity;
2223
import org.apache.http.entity.ContentType;
2324
import org.apache.http.entity.StringEntity;
25+
import org.apache.http.nio.entity.NStringEntity;
26+
import org.elasticsearch.ElasticsearchException;
2427
import org.elasticsearch.ElasticsearchStatusException;
28+
import org.elasticsearch.action.search.ClearScrollRequest;
29+
import org.elasticsearch.action.search.ClearScrollResponse;
2530
import org.elasticsearch.action.search.SearchRequest;
2631
import org.elasticsearch.action.search.SearchResponse;
32+
import org.elasticsearch.action.search.SearchScrollRequest;
33+
import org.elasticsearch.common.unit.TimeValue;
34+
import org.elasticsearch.common.xcontent.XContentBuilder;
2735
import org.elasticsearch.index.query.MatchQueryBuilder;
2836
import org.elasticsearch.join.aggregations.Children;
2937
import org.elasticsearch.join.aggregations.ChildrenAggregationBuilder;
@@ -37,6 +45,7 @@
3745
import org.elasticsearch.search.aggregations.matrix.stats.MatrixStatsAggregationBuilder;
3846
import org.elasticsearch.search.aggregations.support.ValueType;
3947
import org.elasticsearch.search.builder.SearchSourceBuilder;
48+
import org.elasticsearch.search.sort.SortOrder;
4049
import org.elasticsearch.search.suggest.Suggest;
4150
import org.elasticsearch.search.suggest.SuggestBuilder;
4251
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
@@ -46,11 +55,14 @@
4655
import java.util.Arrays;
4756
import java.util.Collections;
4857

58+
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
4959
import static org.hamcrest.Matchers.both;
60+
import static org.hamcrest.Matchers.containsString;
5061
import static org.hamcrest.Matchers.either;
5162
import static org.hamcrest.Matchers.equalTo;
5263
import static org.hamcrest.Matchers.greaterThan;
5364
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
65+
import static org.hamcrest.Matchers.instanceOf;
5466
import static org.hamcrest.Matchers.lessThan;
5567

5668
public class SearchIT extends ESRestHighLevelClientTestCase {
@@ -386,6 +398,63 @@ public void testSearchWithSuggest() throws IOException {
386398
}
387399
}
388400

401+
public void testSearchScroll() throws Exception {
402+
403+
for (int i = 0; i < 100; i++) {
404+
XContentBuilder builder = jsonBuilder().startObject().field("field", i).endObject();
405+
HttpEntity entity = new NStringEntity(builder.string(), ContentType.APPLICATION_JSON);
406+
client().performRequest("PUT", "test/type1/" + Integer.toString(i), Collections.emptyMap(), entity);
407+
}
408+
client().performRequest("POST", "/test/_refresh");
409+
410+
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(35).sort("field", SortOrder.ASC);
411+
SearchRequest searchRequest = new SearchRequest("test").scroll(TimeValue.timeValueMinutes(2)).source(searchSourceBuilder);
412+
SearchResponse searchResponse = execute(searchRequest, highLevelClient()::search, highLevelClient()::searchAsync);
413+
414+
try {
415+
long counter = 0;
416+
assertSearchHeader(searchResponse);
417+
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
418+
assertThat(searchResponse.getHits().getHits().length, equalTo(35));
419+
for (SearchHit hit : searchResponse.getHits()) {
420+
assertThat(((Number) hit.getSortValues()[0]).longValue(), equalTo(counter++));
421+
}
422+
423+
searchResponse = execute(new SearchScrollRequest(searchResponse.getScrollId()).scroll(TimeValue.timeValueMinutes(2)),
424+
highLevelClient()::searchScroll, highLevelClient()::searchScrollAsync);
425+
426+
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
427+
assertThat(searchResponse.getHits().getHits().length, equalTo(35));
428+
for (SearchHit hit : searchResponse.getHits()) {
429+
assertEquals(counter++, ((Number) hit.getSortValues()[0]).longValue());
430+
}
431+
432+
searchResponse = execute(new SearchScrollRequest(searchResponse.getScrollId()).scroll(TimeValue.timeValueMinutes(2)),
433+
highLevelClient()::searchScroll, highLevelClient()::searchScrollAsync);
434+
435+
assertThat(searchResponse.getHits().getTotalHits(), equalTo(100L));
436+
assertThat(searchResponse.getHits().getHits().length, equalTo(30));
437+
for (SearchHit hit : searchResponse.getHits()) {
438+
assertEquals(counter++, ((Number) hit.getSortValues()[0]).longValue());
439+
}
440+
} finally {
441+
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
442+
clearScrollRequest.addScrollId(searchResponse.getScrollId());
443+
ClearScrollResponse clearScrollResponse = execute(clearScrollRequest, highLevelClient()::clearScroll,
444+
highLevelClient()::clearScrollAsync);
445+
assertThat(clearScrollResponse.getNumFreed(), greaterThan(0));
446+
assertTrue(clearScrollResponse.isSucceeded());
447+
448+
SearchScrollRequest scrollRequest = new SearchScrollRequest(searchResponse.getScrollId()).scroll(TimeValue.timeValueMinutes(2));
449+
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> execute(scrollRequest,
450+
highLevelClient()::searchScroll, highLevelClient()::searchScrollAsync));
451+
assertEquals(RestStatus.NOT_FOUND, exception.status());
452+
assertThat(exception.getRootCause(), instanceOf(ElasticsearchException.class));
453+
ElasticsearchException rootCause = (ElasticsearchException) exception.getRootCause();
454+
assertThat(rootCause.getMessage(), containsString("No search context found for"));
455+
}
456+
}
457+
389458
private static void assertSearchHeader(SearchResponse searchResponse) {
390459
assertThat(searchResponse.getTook().nanos(), greaterThanOrEqualTo(0L));
391460
assertEquals(0, searchResponse.getFailedShards());

core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@
5959
public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesRequest> {
6060
private List<AliasActions> allAliasActions = new ArrayList<>();
6161

62-
//indices options that require every specified index to exist, expand wildcards only to open indices and
63-
//don't allow that no indices are resolved from wildcard expressions
64-
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false);
62+
// indices options that require every specified index to exist, expand wildcards only to open
63+
// indices, don't allow that no indices are resolved from wildcard expressions and resolve the
64+
// expressions only against indices
65+
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false, true, false, true);
6566

6667
public IndicesAliasesRequest() {
6768

core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.elasticsearch.common.unit.TimeValue;
4242
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
4343
import org.elasticsearch.common.xcontent.XContent;
44-
import org.elasticsearch.common.xcontent.XContentFactory;
4544
import org.elasticsearch.common.xcontent.XContentParser;
4645
import org.elasticsearch.common.xcontent.XContentType;
4746
import org.elasticsearch.index.VersionType;
@@ -300,10 +299,16 @@ public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Null
300299
if (token == null) {
301300
continue;
302301
}
303-
assert token == XContentParser.Token.START_OBJECT;
302+
if (token != XContentParser.Token.START_OBJECT) {
303+
throw new IllegalArgumentException("Malformed action/metadata line [" + line + "], expected "
304+
+ XContentParser.Token.START_OBJECT + " but found [" + token + "]");
305+
}
304306
// Move to FIELD_NAME, that's the action
305307
token = parser.nextToken();
306-
assert token == XContentParser.Token.FIELD_NAME;
308+
if (token != XContentParser.Token.FIELD_NAME) {
309+
throw new IllegalArgumentException("Malformed action/metadata line [" + line + "], expected "
310+
+ XContentParser.Token.FIELD_NAME + " but found [" + token + "]");
311+
}
307312
String action = parser.currentName();
308313

309314
String index = defaultIndex;

0 commit comments

Comments
 (0)