Skip to content

Commit 6c2ec33

Browse files
authored
Stop returning cluster state size by default (#40016)
Computing the compressed size of the cluster state on every invocation of cluster:monitor/state action is expensive, and the value of this field is dubious anyway. Therefore we want to remove computing this field. As a first step, we stop computing and return this field by default. To avoid breaking users, we will give them a system property to use to tide them over until the next major release when we will actually remove this field. This comes with a deprecation warning too, and the backport to the appropriate minor will also include a note in the migration guide. There will be a follow-up to remove this field in the next major version.
1 parent 2c85601 commit 6c2ec33

File tree

9 files changed

+166
-14
lines changed

9 files changed

+166
-14
lines changed

qa/cluster-state-size/build.gradle

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import org.elasticsearch.gradle.test.RestIntegTestTask
21+
22+
apply plugin: 'elasticsearch.standalone-test'
23+
24+
task integTest(type: RestIntegTestTask) {
25+
mustRunAfter(precommit)
26+
}
27+
28+
integTestCluster {
29+
systemProperty 'es.cluster_state.size', 'true'
30+
}
31+
32+
unitTest.enabled = false
33+
check.dependsOn integTest
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.cluster_state_size;
21+
22+
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
23+
import org.elasticsearch.Version;
24+
import org.elasticsearch.client.RequestOptions;
25+
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
26+
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
27+
28+
import java.util.Collections;
29+
30+
public class ClusterStateSizeRestIT extends ESClientYamlSuiteTestCase {
31+
32+
public ClusterStateSizeRestIT(final ClientYamlTestCandidate candidate) {
33+
super(candidate);
34+
}
35+
36+
@ParametersFactory
37+
public static Iterable<Object[]> parameters() throws Exception {
38+
return ESClientYamlSuiteTestCase.createParameters();
39+
}
40+
41+
@Override
42+
protected RequestOptions getCatNodesVersionMasterRequestOptions() {
43+
final RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
44+
final VersionSensitiveWarningsHandler handler = new VersionSensitiveWarningsHandler(Collections.singleton(Version.CURRENT));
45+
handler.current("es.cluster_state.size is deprecated and will be removed in 7.0.0");
46+
builder.setWarningsHandler(handler);
47+
return builder.build();
48+
}
49+
50+
@Override
51+
protected boolean preserveClusterSettings() {
52+
// we did not add any cluster settings, we are the only test using this cluster, and trying to clean these will trigger a warning
53+
return true;
54+
}
55+
56+
@Override
57+
protected boolean preserveTemplatesUponCompletion() {
58+
// we did not add any templates, we are the only test using this cluster, and trying to clean these will trigger a warning
59+
return true;
60+
}
61+
62+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"get cluster state returns cluster state size with human readable format":
3+
- skip:
4+
reason: deprecation was added in 6.7.0
5+
features: "warnings"
6+
7+
- do:
8+
warnings:
9+
- 'es.cluster_state.size is deprecated and will be removed in 7.0.0'
10+
cluster.state:
11+
human: true
12+
13+
- is_true: master_node
14+
- gte: { compressed_size_in_bytes: 50 }
15+
- is_true: compressed_size

rest-api-spec/src/main/resources/rest-api-spec/test/cluster.state/10_basic.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
- is_true: master_node
77

88
---
9-
"get cluster state returns cluster state size with human readable format":
9+
"get cluster state does not return cluster state size by default":
10+
- skip:
11+
version: " - 7.99.99"
12+
reason: "backwards compatibility break in 6.7.0 removes compressed_size* from the response"
1013
- do:
1114
cluster.state:
1215
human: true
1316

1417
- is_true: master_node
15-
- gte: { compressed_size_in_bytes: 50 }
16-
- is_true: compressed_size
18+
- is_false: compressed_size_in_bytes
19+
- is_false: compressed_size
1720

1821
---
1922
"get cluster state returns cluster_uuid at the top level":
@@ -27,5 +30,3 @@
2730

2831
- is_true: cluster_uuid
2932
- is_true: master_node
30-
- gte: { compressed_size_in_bytes: 50 }
31-
- is_true: compressed_size

server/src/main/java/org/elasticsearch/action/admin/cluster/state/ClusterStateResponse.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public ClusterName getClusterName() {
7373
* of the cluster state as it would be transmitted over the network during
7474
* intra-node communication.
7575
*/
76+
@Deprecated
7677
public ByteSizeValue getTotalCompressedSize() {
7778
return totalCompressedSize;
7879
}

server/src/main/java/org/elasticsearch/action/admin/cluster/state/TransportClusterStateAction.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package org.elasticsearch.action.admin.cluster.state;
2121

2222
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
23+
import org.apache.logging.log4j.LogManager;
24+
import org.apache.logging.log4j.Logger;
2325
import org.elasticsearch.Version;
2426
import org.elasticsearch.action.ActionListener;
2527
import org.elasticsearch.action.support.ActionFilters;
@@ -35,6 +37,7 @@
3537
import org.elasticsearch.cluster.routing.RoutingTable;
3638
import org.elasticsearch.cluster.service.ClusterService;
3739
import org.elasticsearch.common.inject.Inject;
40+
import org.elasticsearch.common.logging.DeprecationLogger;
3841
import org.elasticsearch.common.unit.TimeValue;
3942
import org.elasticsearch.node.NodeClosedException;
4043
import org.elasticsearch.threadpool.ThreadPool;
@@ -45,6 +48,24 @@
4548

4649
public class TransportClusterStateAction extends TransportMasterNodeReadAction<ClusterStateRequest, ClusterStateResponse> {
4750

51+
private final Logger logger = LogManager.getLogger(getClass());
52+
private final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
53+
54+
public static final boolean CLUSTER_STATE_SIZE;
55+
56+
static {
57+
final String property = System.getProperty("es.cluster_state.size");
58+
if (property == null) {
59+
CLUSTER_STATE_SIZE = false;
60+
} else {
61+
final boolean clusterStateSize = Boolean.parseBoolean(property);
62+
if (clusterStateSize) {
63+
CLUSTER_STATE_SIZE = true;
64+
} else {
65+
throw new IllegalArgumentException("es.cluster_state.size can only be unset or [true] but was [" + property + "]");
66+
}
67+
}
68+
}
4869

4970
@Inject
5071
public TransportClusterStateAction(TransportService transportService, ClusterService clusterService,
@@ -182,8 +203,16 @@ private void buildResponse(final ClusterStateRequest request,
182203
}
183204
}
184205
}
185-
listener.onResponse(new ClusterStateResponse(currentState.getClusterName(), builder.build(),
186-
PublicationTransportHandler.serializeFullClusterState(currentState, Version.CURRENT).length(), false));
206+
207+
final long sizeInBytes;
208+
if (CLUSTER_STATE_SIZE) {
209+
deprecationLogger.deprecated("es.cluster_state.size is deprecated and will be removed in 7.0.0");
210+
sizeInBytes = PublicationTransportHandler.serializeFullClusterState(currentState, Version.CURRENT).length();
211+
} else {
212+
sizeInBytes = 0;
213+
}
214+
215+
listener.onResponse(new ClusterStateResponse(currentState.getClusterName(), builder.build(), sizeInBytes, false));
187216
}
188217

189218

server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
2323
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
24+
import org.elasticsearch.action.admin.cluster.state.TransportClusterStateAction;
2425
import org.elasticsearch.action.support.IndicesOptions;
2526
import org.elasticsearch.client.Requests;
2627
import org.elasticsearch.client.node.NodeClient;
@@ -102,8 +103,12 @@ public RestResponse buildResponse(ClusterStateResponse response, XContentBuilder
102103
builder.field(Fields.WAIT_FOR_TIMED_OUT, response.isWaitForTimedOut());
103104
}
104105
builder.field(Fields.CLUSTER_NAME, response.getClusterName().value());
105-
builder.humanReadableField(Fields.CLUSTER_STATE_SIZE_IN_BYTES, Fields.CLUSTER_STATE_SIZE,
106-
response.getTotalCompressedSize());
106+
if (TransportClusterStateAction.CLUSTER_STATE_SIZE) {
107+
builder.humanReadableField(
108+
Fields.CLUSTER_STATE_SIZE_IN_BYTES,
109+
Fields.CLUSTER_STATE_SIZE,
110+
response.getTotalCompressedSize());
111+
}
107112
response.getState().toXContent(builder, request);
108113
builder.endObject();
109114
return new BytesRestResponse(RestStatus.OK, builder);

server/src/test/java/org/elasticsearch/cluster/GetClusterStateTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
2323
import org.elasticsearch.test.ESSingleNodeTestCase;
2424

25-
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
25+
import static org.hamcrest.Matchers.equalTo;
2626

2727
/**
2828
* Tests for the get cluster state API.
@@ -36,8 +36,8 @@ public void testGetClusterState() {
3636
ClusterStateResponse response = client().admin().cluster().prepareState().get();
3737
assertNotNull(response.getState());
3838
assertNotNull(response.getClusterName());
39-
// assume the cluster state size is 50 bytes or more, just so we aren't testing against size of 0
40-
assertThat(response.getTotalCompressedSize().getBytes(), greaterThanOrEqualTo(50L));
39+
// the cluster state size is no longer computed by default
40+
assertThat(response.getTotalCompressedSize().getBytes(), equalTo(0L));
4141
}
4242

4343
public void testSizeDerivedFromFullClusterState() {

test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.Version;
2525
import org.elasticsearch.client.Node;
2626
import org.elasticsearch.client.Request;
27+
import org.elasticsearch.client.RequestOptions;
2728
import org.elasticsearch.client.Response;
2829
import org.elasticsearch.client.RestClient;
2930
import org.elasticsearch.client.RestClientBuilder;
@@ -291,10 +292,11 @@ private static void validateSpec(ClientYamlSuiteRestSpec restSpec) {
291292
}
292293
}
293294

294-
private static Tuple<Version, Version> readVersionsFromCatNodes(RestClient restClient) throws IOException {
295+
private Tuple<Version, Version> readVersionsFromCatNodes(RestClient restClient) throws IOException {
295296
// we simply go to the _cat/nodes API and parse all versions in the cluster
296-
Request request = new Request("GET", "/_cat/nodes");
297+
final Request request = new Request("GET", "/_cat/nodes");
297298
request.addParameter("h", "version,master");
299+
request.setOptions(getCatNodesVersionMasterRequestOptions());
298300
Response response = restClient.performRequest(request);
299301
ClientYamlTestResponse restTestResponse = new ClientYamlTestResponse(response);
300302
String nodesCatResponse = restTestResponse.getBodyAsString();
@@ -319,6 +321,10 @@ private static Tuple<Version, Version> readVersionsFromCatNodes(RestClient restC
319321
return new Tuple<>(version, masterVersion);
320322
}
321323

324+
protected RequestOptions getCatNodesVersionMasterRequestOptions() {
325+
return RequestOptions.DEFAULT;
326+
}
327+
322328
public void test() throws IOException {
323329
//skip test if it matches one of the blacklist globs
324330
for (BlacklistedPathPatternMatcher blacklistedPathMatcher : blacklistPathMatchers) {

0 commit comments

Comments
 (0)