Skip to content

Commit db98fba

Browse files
committed
Run TransportGetMappingsAction on local node
This action solely needs the cluster state, it can run on any node. Additionally, it needs to be cancellable to avoid doing unnecessary work after a client failure or timeout. Relates #101805
1 parent 1c368c7 commit db98fba

File tree

11 files changed

+119
-76
lines changed

11 files changed

+119
-76
lines changed

qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/RestActionCancellationIT.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsAction;
1616
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
1717
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
18+
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction;
1819
import org.elasticsearch.action.admin.indices.recovery.RecoveryAction;
1920
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
2021
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
@@ -108,6 +109,11 @@ public void testGetPipelineCancellation() {
108109
runRestActionCancellationTest(new Request(HttpGet.METHOD_NAME, "/_ingest/pipeline"), GetPipelineAction.NAME);
109110
}
110111

112+
public void testGetMappingsCancellation() {
113+
createIndex("test");
114+
runRestActionCancellationTest(new Request(HttpGet.METHOD_NAME, "/test/_mappings"), GetMappingsAction.NAME);
115+
}
116+
111117
private void runRestActionCancellationTest(Request request, String actionName) {
112118
final var node = usually() ? internalCluster().getRandomNodeName() : internalCluster().startCoordinatingOnlyNode(Settings.EMPTY);
113119

qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/RestClusterInfoActionCancellationIT.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import org.apache.http.client.methods.HttpGet;
1313
import org.elasticsearch.action.admin.indices.get.GetIndexAction;
14-
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction;
1514
import org.elasticsearch.action.support.PlainActionFuture;
1615
import org.elasticsearch.action.support.master.AcknowledgedResponse;
1716
import org.elasticsearch.client.Cancellable;
@@ -41,10 +40,6 @@
4140
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0)
4241
public class RestClusterInfoActionCancellationIT extends HttpSmokeTestCase {
4342

44-
public void testGetMappingsCancellation() throws Exception {
45-
runTest(GetMappingsAction.NAME, "/test/_mappings");
46-
}
47-
4843
public void testGetIndicesCancellation() throws Exception {
4944
runTest(GetIndexAction.NAME, "/test");
5045
}

rest-api-spec/src/main/resources/rest-api-spec/api/indices.get_mapping.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,12 @@
5454
},
5555
"master_timeout":{
5656
"type":"time",
57-
"description":"Specify timeout for connection to master"
57+
"description":"Timeout for waiting for new cluster state in case it is blocked"
5858
},
5959
"local":{
6060
"type":"boolean",
6161
"description":"Return local information, do not retrieve the state from master node (default: false)",
62-
"deprecated":{
63-
"version":"7.8.0",
64-
"description":"This parameter is a no-op and field mappings are always retrieved locally."
65-
}
62+
"deprecated":true
6663
}
6764
}
6865
}

server/src/internalClusterTest/java/org/elasticsearch/action/IndicesRequestIT.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
2525
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsAction;
2626
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
27-
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction;
28-
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
2927
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
3028
import org.elasticsearch.action.admin.indices.mapping.put.TransportPutMappingAction;
3129
import org.elasticsearch.action.admin.indices.open.OpenIndexAction;
@@ -516,16 +514,6 @@ public void testDeleteIndex() {
516514
assertSameIndices(deleteIndexRequest, TransportDeleteIndexAction.TYPE.name());
517515
}
518516

519-
public void testGetMappings() {
520-
interceptTransportActions(GetMappingsAction.NAME);
521-
522-
GetMappingsRequest getMappingsRequest = new GetMappingsRequest(TEST_REQUEST_TIMEOUT).indices(randomIndicesOrAliases());
523-
internalCluster().coordOnlyNodeClient().admin().indices().getMappings(getMappingsRequest).actionGet();
524-
525-
clearInterceptedActions();
526-
assertSameIndices(getMappingsRequest, GetMappingsAction.NAME);
527-
}
528-
529517
public void testPutMapping() {
530518
interceptTransportActions(TransportPutMappingAction.TYPE.name());
531519

server/src/internalClusterTest/java/org/elasticsearch/cluster/SimpleClusterStateIT.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ public void testLargeClusterStatePublishing() throws Exception {
266266
MappingMetadata mappingMetadata = client.admin()
267267
.indices()
268268
.prepareGetMappings(TEST_REQUEST_TIMEOUT, "test")
269-
.setLocal(true)
270269
.get()
271270
.getMappings()
272271
.get("test");

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsRequest.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,44 @@
99

1010
package org.elasticsearch.action.admin.indices.mapping.get;
1111

12+
import org.elasticsearch.TransportVersions;
1213
import org.elasticsearch.action.ActionRequestValidationException;
14+
import org.elasticsearch.action.IndicesRequest;
1315
import org.elasticsearch.action.support.IndicesOptions;
14-
import org.elasticsearch.action.support.master.info.ClusterInfoRequest;
16+
import org.elasticsearch.action.support.local.LocalClusterStateRequest;
17+
import org.elasticsearch.common.Strings;
1518
import org.elasticsearch.common.io.stream.StreamInput;
1619
import org.elasticsearch.core.TimeValue;
20+
import org.elasticsearch.core.UpdateForV10;
1721
import org.elasticsearch.tasks.CancellableTask;
1822
import org.elasticsearch.tasks.Task;
1923
import org.elasticsearch.tasks.TaskId;
2024

2125
import java.io.IOException;
2226
import java.util.Map;
2327

24-
public class GetMappingsRequest extends ClusterInfoRequest<GetMappingsRequest> {
28+
public class GetMappingsRequest extends LocalClusterStateRequest implements IndicesRequest.Replaceable {
29+
30+
private String[] indices = Strings.EMPTY_ARRAY;
31+
private IndicesOptions indicesOptions;
2532

2633
public GetMappingsRequest(TimeValue masterTimeout) {
27-
super(masterTimeout, IndicesOptions.strictExpandOpen());
34+
super(masterTimeout);
35+
indicesOptions = IndicesOptions.strictExpandOpen();
2836
}
2937

38+
/**
39+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC we must remain able to read these requests until
40+
* we no longer need to support calling this action remotely.
41+
*/
42+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
3043
public GetMappingsRequest(StreamInput in) throws IOException {
3144
super(in);
45+
indices = in.readStringArray();
46+
if (in.getTransportVersion().before(TransportVersions.V_8_0_0)) {
47+
in.readStringArray();
48+
}
49+
indicesOptions = IndicesOptions.readIndicesOptions(in);
3250
}
3351

3452
@Override
@@ -40,4 +58,30 @@ public ActionRequestValidationException validate() {
4058
public Task createTask(long id, String type, String action, TaskId parentTaskId, Map<String, String> headers) {
4159
return new CancellableTask(id, type, action, "", parentTaskId, headers);
4260
}
61+
62+
@Override
63+
public GetMappingsRequest indices(String... indices) {
64+
this.indices = indices;
65+
return this;
66+
}
67+
68+
public GetMappingsRequest indicesOptions(IndicesOptions indicesOptions) {
69+
this.indicesOptions = indicesOptions;
70+
return this;
71+
}
72+
73+
@Override
74+
public String[] indices() {
75+
return indices;
76+
}
77+
78+
@Override
79+
public IndicesOptions indicesOptions() {
80+
return indicesOptions;
81+
}
82+
83+
@Override
84+
public boolean includeDataStreams() {
85+
return true;
86+
}
4387
}

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsRequestBuilder.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,30 @@
99

1010
package org.elasticsearch.action.admin.indices.mapping.get;
1111

12-
import org.elasticsearch.action.support.master.info.ClusterInfoRequestBuilder;
12+
import org.elasticsearch.action.ActionRequestBuilder;
13+
import org.elasticsearch.action.support.IndicesOptions;
1314
import org.elasticsearch.client.internal.ElasticsearchClient;
15+
import org.elasticsearch.common.util.ArrayUtils;
1416
import org.elasticsearch.core.TimeValue;
1517

16-
public class GetMappingsRequestBuilder extends ClusterInfoRequestBuilder<
17-
GetMappingsRequest,
18-
GetMappingsResponse,
19-
GetMappingsRequestBuilder> {
18+
public class GetMappingsRequestBuilder extends ActionRequestBuilder<GetMappingsRequest, GetMappingsResponse> {
2019

2120
public GetMappingsRequestBuilder(ElasticsearchClient client, TimeValue masterTimeout, String... indices) {
2221
super(client, GetMappingsAction.INSTANCE, new GetMappingsRequest(masterTimeout).indices(indices));
2322
}
23+
24+
public GetMappingsRequestBuilder setIndices(String... indices) {
25+
request.indices(indices);
26+
return this;
27+
}
28+
29+
public GetMappingsRequestBuilder addIndices(String... indices) {
30+
request.indices(ArrayUtils.concat(request.indices(), indices));
31+
return this;
32+
}
33+
34+
public GetMappingsRequestBuilder setIndicesOptions(IndicesOptions indicesOptions) {
35+
request.indicesOptions(indicesOptions);
36+
return this;
37+
}
2438
}

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetMappingsResponse.java

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@
99

1010
package org.elasticsearch.action.admin.indices.mapping.get;
1111

12-
import org.elasticsearch.TransportVersions;
1312
import org.elasticsearch.action.ActionResponse;
1413
import org.elasticsearch.cluster.metadata.MappingMetadata;
1514
import org.elasticsearch.common.Strings;
1615
import org.elasticsearch.common.collect.Iterators;
17-
import org.elasticsearch.common.io.stream.StreamInput;
1816
import org.elasticsearch.common.io.stream.StreamOutput;
1917
import org.elasticsearch.common.xcontent.ChunkedToXContentObject;
20-
import org.elasticsearch.index.mapper.MapperService;
18+
import org.elasticsearch.core.UpdateForV10;
2119
import org.elasticsearch.xcontent.ParseField;
2220
import org.elasticsearch.xcontent.ToXContent;
2321

@@ -35,21 +33,6 @@ public GetMappingsResponse(Map<String, MappingMetadata> mappings) {
3533
this.mappings = mappings;
3634
}
3735

38-
GetMappingsResponse(StreamInput in) throws IOException {
39-
super(in);
40-
mappings = in.readImmutableMap(in.getTransportVersion().before(TransportVersions.V_8_0_0) ? i -> {
41-
int mappingCount = i.readVInt();
42-
assert mappingCount == 1 || mappingCount == 0 : "Expected 0 or 1 mappings but got " + mappingCount;
43-
if (mappingCount == 1) {
44-
String type = i.readString();
45-
assert MapperService.SINGLE_MAPPING_NAME.equals(type) : "Expected type [_doc] but got [" + type + "]";
46-
return new MappingMetadata(i);
47-
} else {
48-
return MappingMetadata.EMPTY_MAPPINGS;
49-
}
50-
} : i -> i.readBoolean() ? new MappingMetadata(i) : MappingMetadata.EMPTY_MAPPINGS);
51-
}
52-
5336
public Map<String, MappingMetadata> mappings() {
5437
return mappings;
5538
}
@@ -58,6 +41,11 @@ public Map<String, MappingMetadata> getMappings() {
5841
return mappings();
5942
}
6043

44+
/**
45+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC we must remain able to write these responses until
46+
* we no longer need to support calling this action remotely.
47+
*/
48+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
6149
@Override
6250
public void writeTo(StreamOutput out) throws IOException {
6351
MappingMetadata.writeMappingMetadata(out, mappings);

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetMappingsAction.java

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@
1313
import org.apache.logging.log4j.Logger;
1414
import org.elasticsearch.action.ActionListener;
1515
import org.elasticsearch.action.support.ActionFilters;
16-
import org.elasticsearch.action.support.master.info.TransportClusterInfoAction;
16+
import org.elasticsearch.action.support.ChannelActionListener;
17+
import org.elasticsearch.action.support.local.TransportLocalClusterStateAction;
1718
import org.elasticsearch.cluster.ClusterState;
19+
import org.elasticsearch.cluster.block.ClusterBlockException;
20+
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1821
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
1922
import org.elasticsearch.cluster.metadata.MappingMetadata;
2023
import org.elasticsearch.cluster.metadata.Metadata;
2124
import org.elasticsearch.cluster.service.ClusterService;
25+
import org.elasticsearch.core.UpdateForV10;
2226
import org.elasticsearch.indices.IndicesService;
2327
import org.elasticsearch.injection.guice.Inject;
2428
import org.elasticsearch.tasks.CancellableTask;
@@ -28,12 +32,19 @@
2832

2933
import java.util.Map;
3034

31-
public class TransportGetMappingsAction extends TransportClusterInfoAction<GetMappingsRequest, GetMappingsResponse> {
35+
public class TransportGetMappingsAction extends TransportLocalClusterStateAction<GetMappingsRequest, GetMappingsResponse> {
3236

3337
private static final Logger logger = LogManager.getLogger(TransportGetMappingsAction.class);
3438

3539
private final IndicesService indicesService;
40+
private final IndexNameExpressionResolver indexNameExpressionResolver;
3641

42+
/**
43+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC it must be registered with the TransportService until
44+
* we no longer need to support calling this action remotely.
45+
*/
46+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
47+
@SuppressWarnings("this-escape")
3748
@Inject
3849
public TransportGetMappingsAction(
3950
TransportService transportService,
@@ -45,26 +56,39 @@ public TransportGetMappingsAction(
4556
) {
4657
super(
4758
GetMappingsAction.NAME,
48-
transportService,
49-
clusterService,
50-
threadPool,
5159
actionFilters,
52-
GetMappingsRequest::new,
53-
indexNameExpressionResolver,
54-
GetMappingsResponse::new
60+
transportService.getTaskManager(),
61+
clusterService,
62+
threadPool.executor(ThreadPool.Names.MANAGEMENT)
5563
);
5664
this.indicesService = indicesService;
65+
this.indexNameExpressionResolver = indexNameExpressionResolver;
66+
67+
transportService.registerRequestHandler(
68+
actionName,
69+
executor,
70+
false,
71+
true,
72+
GetMappingsRequest::new,
73+
(request, channel, task) -> executeDirect(task, request, new ChannelActionListener<>(channel))
74+
);
75+
}
76+
77+
@Override
78+
protected ClusterBlockException checkBlock(GetMappingsRequest request, ClusterState state) {
79+
return state.blocks()
80+
.indicesBlockedException(ClusterBlockLevel.METADATA_READ, indexNameExpressionResolver.concreteIndexNames(state, request));
5781
}
5882

5983
@Override
60-
protected void doMasterOperation(
84+
protected void localClusterStateOperation(
6185
Task task,
6286
final GetMappingsRequest request,
63-
String[] concreteIndices,
6487
final ClusterState state,
6588
final ActionListener<GetMappingsResponse> listener
6689
) {
6790
logger.trace("serving getMapping request based on version {}", state.version());
91+
String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(state, request);
6892
final Metadata metadata = state.metadata();
6993
final Map<String, MappingMetadata> mappings = metadata.findMappings(
7094
concreteIndices,

server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.http.HttpChannel;
1717
import org.elasticsearch.rest.BaseRestHandler;
1818
import org.elasticsearch.rest.RestRequest;
19+
import org.elasticsearch.rest.RestUtils;
1920
import org.elasticsearch.rest.Scope;
2021
import org.elasticsearch.rest.ServerlessScope;
2122
import org.elasticsearch.rest.action.RestCancellableNodeClient;
@@ -25,7 +26,6 @@
2526
import java.util.List;
2627

2728
import static org.elasticsearch.rest.RestRequest.Method.GET;
28-
import static org.elasticsearch.rest.RestUtils.getMasterNodeTimeout;
2929

3030
@ServerlessScope(Scope.PUBLIC)
3131
public class RestGetMappingAction extends BaseRestHandler {
@@ -50,10 +50,10 @@ public String getName() {
5050
@Override
5151
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
5252
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
53-
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest(getMasterNodeTimeout(request));
53+
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest(RestUtils.getMasterNodeTimeout(request));
5454
getMappingsRequest.indices(indices);
5555
getMappingsRequest.indicesOptions(IndicesOptions.fromRequest(request, getMappingsRequest.indicesOptions()));
56-
getMappingsRequest.local(request.paramAsBoolean("local", getMappingsRequest.local()));
56+
RestUtils.consumeDeprecatedLocalParameter(request);
5757
final HttpChannel httpChannel = request.getHttpChannel();
5858
return channel -> new RestCancellableNodeClient(client, httpChannel).admin()
5959
.indices()

0 commit comments

Comments
 (0)