Skip to content

Commit

Permalink
REST high-level client: add clear cache API (#28866)
Browse files Browse the repository at this point in the history
Relates to #27205

Also Closes #26947 (rest-spec were outdated)
  • Loading branch information
javanna committed Mar 20, 2018
1 parent 9a463fd commit 9f65252
Show file tree
Hide file tree
Showing 11 changed files with 620 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
Expand Down Expand Up @@ -259,6 +261,29 @@ public void flushAsync(FlushRequest flushRequest, ActionListener<FlushResponse>
listener, emptySet(), headers);
}

/**
* Clears the cache of one or more indices using the Clear Cache API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
* Clear Cache API on elastic.co</a>
*/
public ClearIndicesCacheResponse clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest, Header... headers) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
ClearIndicesCacheResponse::fromXContent, emptySet(), headers);
}

/**
* Asynchronously clears the cache of one or more indices using the Clear Cache API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
* Clear Cache API on elastic.co</a>
*/
public void clearCacheAsync(ClearIndicesCacheRequest clearIndicesCacheRequest, ActionListener<ClearIndicesCacheResponse> listener,
Header... headers) {
restHighLevelClient.performRequestAsyncAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
ClearIndicesCacheResponse::fromXContent, listener, emptySet(), headers);
}

/**
* Checks if the index (indices) exists or not.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
Expand Down Expand Up @@ -170,13 +171,10 @@ static Request openIndex(OpenIndexRequest openIndexRequest) {

static Request closeIndex(CloseIndexRequest closeIndexRequest) {
String endpoint = endpoint(closeIndexRequest.indices(), "_close");

Params parameters = Params.builder();

parameters.withTimeout(closeIndexRequest.timeout());
parameters.withMasterTimeout(closeIndexRequest.masterNodeTimeout());
parameters.withIndicesOptions(closeIndexRequest.indicesOptions());

return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}

Expand Down Expand Up @@ -220,21 +218,35 @@ static Request putMapping(PutMappingRequest putMappingRequest) throws IOExceptio
}

static Request refresh(RefreshRequest refreshRequest) {
String endpoint = endpoint(refreshRequest.indices(), "_refresh");
String[] indices = refreshRequest.indices() == null ? Strings.EMPTY_ARRAY : refreshRequest.indices();
String endpoint = endpoint(indices, "_refresh");
Params parameters = Params.builder();
parameters.withIndicesOptions(refreshRequest.indicesOptions());
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}

static Request flush(FlushRequest flushRequest) {
String endpoint = endpoint(flushRequest.indices(), "_flush");
String[] indices = flushRequest.indices() == null ? Strings.EMPTY_ARRAY : flushRequest.indices();
String endpoint = endpoint(indices, "_flush");
Params parameters = Params.builder();
parameters.withIndicesOptions(flushRequest.indicesOptions());
parameters.putParam("wait_if_ongoing", Boolean.toString(flushRequest.waitIfOngoing()));
parameters.putParam("force", Boolean.toString(flushRequest.force()));
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}

static Request clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest) {
String[] indices = clearIndicesCacheRequest.indices() == null ? Strings.EMPTY_ARRAY :clearIndicesCacheRequest.indices();
String endpoint = endpoint(indices, "_cache/clear");
Params parameters = Params.builder();
parameters.withIndicesOptions(clearIndicesCacheRequest.indicesOptions());
parameters.putParam("query", Boolean.toString(clearIndicesCacheRequest.queryCache()));
parameters.putParam("fielddata", Boolean.toString(clearIndicesCacheRequest.fieldDataCache()));
parameters.putParam("request", Boolean.toString(clearIndicesCacheRequest.requestCache()));
parameters.putParam("fields", String.join(",", clearIndicesCacheRequest.fields()));
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}

static Request info() {
return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null);
}
Expand Down Expand Up @@ -510,10 +522,13 @@ static Request existsAlias(GetAliasesRequest getAliasesRequest) {
Params params = Params.builder();
params.withIndicesOptions(getAliasesRequest.indicesOptions());
params.withLocal(getAliasesRequest.local());
if (getAliasesRequest.indices().length == 0 && getAliasesRequest.aliases().length == 0) {
if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
(getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) {
throw new IllegalArgumentException("existsAlias requires at least an alias or an index");
}
String endpoint = endpoint(getAliasesRequest.indices(), "_alias", getAliasesRequest.aliases());
String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices();
String[] aliases = getAliasesRequest.aliases() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.aliases();
String endpoint = endpoint(indices, "_alias", aliases);
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}

Expand Down Expand Up @@ -542,8 +557,9 @@ private static Request resize(ResizeRequest resizeRequest) throws IOException {
params.withTimeout(resizeRequest.timeout());
params.withMasterTimeout(resizeRequest.masterNodeTimeout());
params.withWaitForActiveShards(resizeRequest.getTargetIndexRequest().waitForActiveShards(), ActiveShardCount.DEFAULT);
String endpoint = buildEndpoint(resizeRequest.getSourceIndex(), "_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT),
resizeRequest.getTargetIndexRequest().index());
String endpoint = new EndpointBuilder().addPathPart(resizeRequest.getSourceIndex())
.addPathPartAsIs("_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT))
.addPathPart(resizeRequest.getTargetIndexRequest().index()).build();
HttpEntity entity = createEntity(resizeRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPut.METHOD_NAME, endpoint, params.getParams(), entity);
}
Expand All @@ -553,10 +569,8 @@ static Request clusterPutSettings(ClusterUpdateSettingsRequest clusterUpdateSett
parameters.withFlatSettings(clusterUpdateSettingsRequest.flatSettings());
parameters.withTimeout(clusterUpdateSettingsRequest.timeout());
parameters.withMasterTimeout(clusterUpdateSettingsRequest.masterNodeTimeout());

String endpoint = buildEndpoint("_cluster", "settings");
HttpEntity entity = createEntity(clusterUpdateSettingsRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity);
return new Request(HttpPut.METHOD_NAME, "/_cluster/settings", parameters.getParams(), entity);
}

static Request rollover(RolloverRequest rolloverRequest) throws IOException {
Expand All @@ -567,64 +581,60 @@ static Request rollover(RolloverRequest rolloverRequest) throws IOException {
if (rolloverRequest.isDryRun()) {
params.putParam("dry_run", Boolean.TRUE.toString());
}
String endpoint = buildEndpoint(rolloverRequest.getAlias(), "_rollover", rolloverRequest.getNewIndexName());
String endpoint = new EndpointBuilder().addPathPart(rolloverRequest.getAlias()).addPathPartAsIs("_rollover")
.addPathPart(rolloverRequest.getNewIndexName()).build();
HttpEntity entity = createEntity(rolloverRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPost.METHOD_NAME, endpoint, params.getParams(), entity);
}

static Request indicesExist(GetIndexRequest request) {
//this can be called with no indices as argument by transport client, not via REST though
if (request.indices() == null || request.indices().length == 0) {
throw new IllegalArgumentException("indices are mandatory");
}
String endpoint = endpoint(request.indices(), "");
Params params = Params.builder();
params.withLocal(request.local());
params.withHuman(request.humanReadable());
params.withIndicesOptions(request.indicesOptions());
params.withFlatSettings(request.flatSettings());
params.withIncludeDefaults(request.includeDefaults());
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}

private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
}

static String endpoint(String index, String type, String id) {
return buildEndpoint(index, type, id);
return new EndpointBuilder().addPathPart(index, type, id).build();
}

static String endpoint(String index, String type, String id, String endpoint) {
return buildEndpoint(index, type, id, endpoint);
return new EndpointBuilder().addPathPart(index, type, id).addPathPartAsIs(endpoint).build();
}

static String endpoint(String[] indices) {
return buildEndpoint(String.join(",", indices));
return new EndpointBuilder().addCommaSeparatedPathParts(indices).build();
}

static String endpoint(String[] indices, String endpoint) {
return buildEndpoint(String.join(",", indices), endpoint);
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).build();
}

static String endpoint(String[] indices, String[] types, String endpoint) {
return buildEndpoint(String.join(",", indices), String.join(",", types), endpoint);
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addCommaSeparatedPathParts(types)
.addPathPartAsIs(endpoint).build();
}

static String endpoint(String[] indices, String endpoint, String[] suffixes) {
return buildEndpoint(String.join(",", indices), endpoint, String.join(",", suffixes));
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint)
.addCommaSeparatedPathParts(suffixes).build();
}

static String endpoint(String[] indices, String endpoint, String type) {
return endpoint(String.join(",", indices), endpoint, type);
}

/**
* Utility method to build request's endpoint given its parts as strings
*/
static String buildEndpoint(String... parts) {
StringJoiner joiner = new StringJoiner("/", "/", "");
for (String part : parts) {
if (Strings.hasLength(part)) {
try {
//encode each part (e.g. index, type and id) separately before merging them into the path
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
//paths that start with `-` or contain `:`
URI uri = new URI(null, null, null, -1, "/" + part, null, null);
//manually encode any slash that each part may contain
joiner.add(uri.getRawPath().substring(1).replaceAll("/", "%2F"));
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Path part [" + part + "] couldn't be encoded", e);
}
}
}
return joiner.toString();
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).addPathPart(type).build();
}

/**
Expand All @@ -638,17 +648,6 @@ public static ContentType createContentType(final XContentType xContentType) {
return ContentType.create(xContentType.mediaTypeWithoutParameters(), (Charset) null);
}

static Request indicesExist(GetIndexRequest request) {
String endpoint = endpoint(request.indices(), Strings.EMPTY_ARRAY, "");
Params params = Params.builder();
params.withLocal(request.local());
params.withHuman(request.humanReadable());
params.withIndicesOptions(request.indicesOptions());
params.withFlatSettings(request.flatSettings());
params.withIncludeDefaults(request.includeDefaults());
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}

/**
* Utility class to build request's parameters map and centralize all parameter names.
*/
Expand Down Expand Up @@ -861,4 +860,50 @@ static XContentType enforceSameContentType(IndexRequest indexRequest, @Nullable
}
return xContentType;
}

/**
* Utility class to build request's endpoint given its parts as strings
*/
static class EndpointBuilder {

private final StringJoiner joiner = new StringJoiner("/", "/", "");

EndpointBuilder addPathPart(String... parts) {
for (String part : parts) {
if (Strings.hasLength(part)) {
joiner.add(encodePart(part));
}
}
return this;
}

EndpointBuilder addCommaSeparatedPathParts(String[] parts) {
addPathPart(String.join(",", parts));
return this;
}

EndpointBuilder addPathPartAsIs(String part) {
if (Strings.hasLength(part)) {
joiner.add(part);
}
return this;
}

String build() {
return joiner.toString();
}

private static String encodePart(String pathPart) {
try {
//encode each part (e.g. index, type and id) separately before merging them into the path
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
//paths that start with `-` or contain `:`
URI uri = new URI(null, null, null, -1, "/" + pathPart, null, null);
//manually encode any slash that each part may contain
return uri.getRawPath().substring(1).replaceAll("/", "%2F");
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Path part [" + pathPart + "] couldn't be encoded", e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
Expand Down Expand Up @@ -433,9 +435,36 @@ public void testFlush() throws IOException {
{
String nonExistentIndex = "non_existent_index";
assertFalse(indexExists(nonExistentIndex));
FlushRequest refreshRequest = new FlushRequest(nonExistentIndex);
FlushRequest flushRequest = new FlushRequest(nonExistentIndex);
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(refreshRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
() -> execute(flushRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
}
}

public void testClearCache() throws IOException {
{
String index = "index";
Settings settings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(index, settings);
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(index);
ClearIndicesCacheResponse clearCacheResponse =
execute(clearCacheRequest, highLevelClient().indices()::clearCache, highLevelClient().indices()::clearCacheAsync);
assertThat(clearCacheResponse.getTotalShards(), equalTo(1));
assertThat(clearCacheResponse.getSuccessfulShards(), equalTo(1));
assertThat(clearCacheResponse.getFailedShards(), equalTo(0));
assertThat(clearCacheResponse.getShardFailures(), equalTo(BroadcastResponse.EMPTY));
}
{
String nonExistentIndex = "non_existent_index";
assertFalse(indexExists(nonExistentIndex));
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(nonExistentIndex);
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(clearCacheRequest, highLevelClient().indices()::clearCache,
highLevelClient().indices()::clearCacheAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
}
}
Expand Down
Loading

0 comments on commit 9f65252

Please sign in to comment.