Skip to content

Avoid extra allocations in RestGetAliasesAction #126177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -84,59 +85,28 @@ static RestResponse buildRestResponse(
) throws Exception {
final Set<String> indicesToDisplay = new HashSet<>();
final Set<String> returnedAliasNames = new HashSet<>();
for (final Map.Entry<String, List<AliasMetadata>> cursor : responseAliasMap.entrySet()) {
for (final AliasMetadata aliasMetadata : cursor.getValue()) {
if (aliasesExplicitlyRequested) {
if (aliasesExplicitlyRequested) {
for (final Map.Entry<String, List<AliasMetadata>> cursor : responseAliasMap.entrySet()) {
final var aliases = cursor.getValue();
if (aliases.isEmpty() == false) {
// only display indices that have aliases
indicesToDisplay.add(cursor.getKey());
}
returnedAliasNames.add(aliasMetadata.alias());
}
}
dataStreamAliases.entrySet()
.stream()
.flatMap(entry -> entry.getValue().stream())
.forEach(dataStreamAlias -> returnedAliasNames.add(dataStreamAlias.getName()));

// compute explicitly requested aliases that have are not returned in the result
final SortedSet<String> missingAliases = new TreeSet<>();
// first wildcard index, leading "-" as an alias name after this index means
// that it is an exclusion
int firstWildcardIndex = requestedAliases.length;
for (int i = 0; i < requestedAliases.length; i++) {
if (Regex.isSimpleMatchPattern(requestedAliases[i])) {
firstWildcardIndex = i;
break;
}
}
for (int i = 0; i < requestedAliases.length; i++) {
if (Metadata.ALL.equals(requestedAliases[i])
|| Regex.isSimpleMatchPattern(requestedAliases[i])
|| (i > firstWildcardIndex && requestedAliases[i].charAt(0) == '-')) {
// only explicitly requested aliases will be called out as missing (404)
continue;
}
// check if aliases[i] is subsequently excluded
int j = Math.max(i + 1, firstWildcardIndex);
for (; j < requestedAliases.length; j++) {
if (requestedAliases[j].charAt(0) == '-') {
// this is an exclude pattern
if (Regex.simpleMatch(requestedAliases[j].substring(1), requestedAliases[i])
|| Metadata.ALL.equals(requestedAliases[j].substring(1))) {
// aliases[i] is excluded by aliases[j]
break;
for (final AliasMetadata aliasMetadata : aliases) {
returnedAliasNames.add(aliasMetadata.alias());
}
}
}
if (j == requestedAliases.length) {
// explicitly requested aliases[i] is not excluded by any subsequent "-" wildcard in expression
if (false == returnedAliasNames.contains(requestedAliases[i])) {
// aliases[i] is not in the result set
missingAliases.add(requestedAliases[i]);

for (final List<DataStreamAlias> dataStreamAliasList : dataStreamAliases.values()) {
for (final DataStreamAlias dataStreamAlias : dataStreamAliasList) {
returnedAliasNames.add(dataStreamAlias.getName());
}
}
}

// compute explicitly requested aliases that would not be returned in the result
final var missingAliases = computeMissingAliases(requestedAliases, returnedAliasNames);

final RestStatus status;
builder.startObject();
{
Expand Down Expand Up @@ -239,4 +209,50 @@ public RestResponse buildResponse(GetAliasesResponse response, XContentBuilder b
});
}

private static SortedSet<String> computeMissingAliases(String[] requestedAliases, Set<String> returnedAliasNames) {
if (requestedAliases.length == 0) {
return Collections.emptySortedSet();
}

final var missingAliases = new TreeSet<String>();

// first wildcard index, leading "-" as an alias name after this index means
// that it is an exclusion
int firstWildcardIndex = requestedAliases.length;
for (int i = 0; i < requestedAliases.length; i++) {
if (Regex.isSimpleMatchPattern(requestedAliases[i])) {
firstWildcardIndex = i;
break;
}
}
for (int i = 0; i < requestedAliases.length; i++) {
if (Metadata.ALL.equals(requestedAliases[i])
|| Regex.isSimpleMatchPattern(requestedAliases[i])
|| (i > firstWildcardIndex && requestedAliases[i].charAt(0) == '-')) {
// only explicitly requested aliases will be called out as missing (404)
continue;
}
// check if aliases[i] is subsequently excluded
int j = Math.max(i + 1, firstWildcardIndex);
for (; j < requestedAliases.length; j++) {
if (requestedAliases[j].charAt(0) == '-') {
// this is an exclude pattern
if (Regex.simpleMatch(requestedAliases[j].substring(1), requestedAliases[i])
|| Metadata.ALL.equals(requestedAliases[j].substring(1))) {
// aliases[i] is excluded by aliases[j]
break;
}
}
}
if (j == requestedAliases.length) {
// explicitly requested aliases[i] is not excluded by any subsequent "-" wildcard in expression
if (false == returnedAliasNames.contains(requestedAliases[i])) {
// aliases[i] is not in the result set
missingAliases.add(requestedAliases[i]);
}
}
}

return missingAliases;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.elasticsearch.xcontent.XContentType;
Expand Down Expand Up @@ -51,6 +52,27 @@ public void testBareRequest() throws Exception {
assertThat(restResponse.content().utf8ToString(), equalTo("{\"index\":{\"aliases\":{\"foo\":{},\"foobar\":{}}}}"));
}

public void testNameParamWithAllValue() throws Exception {
final XContentBuilder xContentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
final var req = new FakeRestRequest.Builder(xContentRegistry()).withParams(Map.of("name", "_all")).build();
final RestResponse restResponse = RestGetAliasesAction.buildRestResponse(
req.hasParam("name"),
req.paramAsStringArrayOrEmptyIfAll("name"),
Map.of(
"index",
Arrays.asList(AliasMetadata.builder("foo").build(), AliasMetadata.builder("foobar").build()),
"index2",
List.of()
),
Map.of(),
xContentBuilder
);
assertThat(restResponse.status(), equalTo(OK));
assertThat(restResponse.contentType(), equalTo("application/json"));
// Verify we don't get "index2" since it has no aliases.
assertThat(restResponse.content().utf8ToString(), equalTo("{\"index\":{\"aliases\":{\"foo\":{},\"foobar\":{}}}}"));
}

public void testSimpleAliasWildcardMatchingNothing() throws Exception {
final XContentBuilder xContentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
final RestResponse restResponse = RestGetAliasesAction.buildRestResponse(
Expand Down