diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java index 0305f123bba11..9b5047b9937b4 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponse.java @@ -10,9 +10,11 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.collect.Iterators; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.ChunkedToXContent; import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; @@ -23,10 +25,11 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Objects; -public class GetSettingsResponse extends ActionResponse implements ToXContentObject { +public class GetSettingsResponse extends ActionResponse implements ToXContentObject, ChunkedToXContent { private final Map indexToSettings; private final Map indexToDefaultSettings; @@ -44,25 +47,12 @@ public GetSettingsResponse(StreamInput in) throws IOException { /** * Returns a map of index name to {@link Settings} object. The returned {@link Settings} - * objects contain only those settings explicitly set on a given index. Any settings - * taking effect as defaults must be accessed via {@link #getIndexToDefaultSettings()}. + * objects contain only those settings explicitly set on a given index. */ public Map getIndexToSettings() { return indexToSettings; } - /** - * If the originating {@link GetSettingsRequest} object was configured to include - * defaults, this will contain a mapping of index name to {@link Settings} objects. - * The returned {@link Settings} objects will contain only those settings taking - * effect as defaults. Any settings explicitly set on the index will be available - * via {@link #getIndexToSettings()}. - * See also {@link GetSettingsRequest#includeDefaults(boolean)} - */ - public Map getIndexToDefaultSettings() { - return indexToDefaultSettings; - } - /** * Returns the string value for the specified index and setting. If the includeDefaults * flag was not set or set to false on the GetSettingsRequest, this method will only @@ -154,7 +144,10 @@ public String toString() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); XContentBuilder builder = new XContentBuilder(JsonXContent.jsonXContent, baos); - toXContent(builder, ToXContent.EMPTY_PARAMS, false); + var iterator = toXContentChunked(false); + while (iterator.hasNext()) { + iterator.next().toXContent(builder, ToXContent.EMPTY_PARAMS); + } return Strings.toString(builder); } catch (IOException e) { throw new IllegalStateException(e); // should not be possible here @@ -162,30 +155,33 @@ public String toString() { } @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return toXContent(builder, params, indexToDefaultSettings.isEmpty()); + public Iterator toXContentChunked() { + final boolean omitEmptySettings = indexToDefaultSettings.isEmpty(); + return toXContentChunked(omitEmptySettings); } - private XContentBuilder toXContent(XContentBuilder builder, Params params, boolean omitEmptySettings) throws IOException { - builder.startObject(); - for (Map.Entry cursor : getIndexToSettings().entrySet()) { - // no settings, jump over it to shorten the response data - if (omitEmptySettings && cursor.getValue().isEmpty()) { - continue; - } - builder.startObject(cursor.getKey()); - builder.startObject("settings"); - cursor.getValue().toXContent(builder, params); - builder.endObject(); - if (indexToDefaultSettings.isEmpty() == false) { - builder.startObject("defaults"); - indexToDefaultSettings.get(cursor.getKey()).toXContent(builder, params); - builder.endObject(); - } - builder.endObject(); - } - builder.endObject(); - return builder; + private Iterator toXContentChunked(boolean omitEmptySettings) { + final boolean indexToDefaultSettingsEmpty = indexToDefaultSettings.isEmpty(); + return Iterators.concat( + Iterators.single((builder, params) -> builder.startObject()), + getIndexToSettings().entrySet() + .stream() + .filter(entry -> omitEmptySettings == false || entry.getValue().isEmpty() == false) + .map(entry -> (ToXContent) (builder, params) -> { + builder.startObject(entry.getKey()); + builder.startObject("settings"); + entry.getValue().toXContent(builder, params); + builder.endObject(); + if (indexToDefaultSettingsEmpty == false) { + builder.startObject("defaults"); + indexToDefaultSettings.get(entry.getKey()).toXContent(builder, params); + builder.endObject(); + } + return builder.endObject(); + }) + .iterator(), + Iterators.single((builder, params) -> builder.endObject()) + ); } @Override diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetSettingsAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetSettingsAction.java index b9b244c7d2c35..a7f1b5dabf243 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetSettingsAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetSettingsAction.java @@ -14,7 +14,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; -import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.rest.action.RestChunkedToXContentListener; import java.io.IOException; import java.util.List; @@ -52,6 +52,6 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC .names(names); getSettingsRequest.local(request.paramAsBoolean("local", getSettingsRequest.local())); getSettingsRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getSettingsRequest.masterNodeTimeout())); - return channel -> client.admin().indices().getSettings(getSettingsRequest, new RestToXContentListener<>(channel)); + return channel -> client.admin().indices().getSettings(getSettingsRequest, new RestChunkedToXContentListener<>(channel)); } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java index 2764eeaa2a11a..8e904db944417 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/settings/get/GetSettingsResponseTests.java @@ -74,4 +74,15 @@ protected Predicate getRandomFieldsExcludeFilter() { return f -> f.equals("") || f.contains(".settings") || f.contains(".defaults"); } + public void testOneChunkPerIndex() { + final var instance = createTestInstance(); + final var iterator = instance.toXContentChunked(); + int chunks = 0; + while (iterator.hasNext()) { + chunks++; + iterator.next(); + } + assertEquals(2 + instance.getIndexToSettings().size(), chunks); + } + }