13
13
import org .elasticsearch .action .ActionRunnable ;
14
14
import org .elasticsearch .action .NoShardAvailableActionException ;
15
15
import org .elasticsearch .action .support .ActionFilters ;
16
+ import org .elasticsearch .action .support .ChannelActionListener ;
16
17
import org .elasticsearch .action .support .HandledTransportAction ;
17
18
import org .elasticsearch .action .support .TransportActions ;
18
19
import org .elasticsearch .cluster .ClusterState ;
26
27
import org .elasticsearch .cluster .service .ClusterService ;
27
28
import org .elasticsearch .common .io .stream .StreamInput ;
28
29
import org .elasticsearch .common .io .stream .Writeable ;
30
+ import org .elasticsearch .common .util .concurrent .EsExecutors ;
29
31
import org .elasticsearch .core .Nullable ;
30
32
import org .elasticsearch .tasks .Task ;
31
33
import org .elasticsearch .threadpool .ThreadPool ;
32
- import org .elasticsearch .transport .TransportChannel ;
33
- import org .elasticsearch .transport .TransportRequestHandler ;
34
34
import org .elasticsearch .transport .TransportService ;
35
+ import org .elasticsearch .transport .Transports ;
35
36
36
37
import java .io .IOException ;
38
+ import java .util .concurrent .Executor ;
37
39
import java .util .concurrent .atomic .AtomicInteger ;
38
40
import java .util .concurrent .atomic .AtomicReferenceArray ;
39
41
@@ -49,31 +51,47 @@ public abstract class TransportBroadcastAction<
49
51
protected final TransportService transportService ;
50
52
protected final IndexNameExpressionResolver indexNameExpressionResolver ;
51
53
52
- final String transportShardAction ;
53
- private final String shardExecutor ;
54
+ private final String transportShardAction ;
55
+ private final Executor executor ;
54
56
55
57
protected TransportBroadcastAction (
56
58
String actionName ,
57
59
ClusterService clusterService ,
58
60
TransportService transportService ,
59
61
ActionFilters actionFilters ,
60
62
IndexNameExpressionResolver indexNameExpressionResolver ,
61
- Writeable .Reader <Request > request ,
62
- Writeable .Reader <ShardRequest > shardRequest ,
63
- String shardExecutor
63
+ Writeable .Reader <Request > requestReader ,
64
+ Writeable .Reader <ShardRequest > shardRequestReader ,
65
+ String executor
64
66
) {
65
- super (actionName , transportService , actionFilters , request );
67
+ // TODO replace SAME when removing workaround for https://github.com/elastic/elasticsearch/issues/97916
68
+ super (actionName , transportService , actionFilters , requestReader , ThreadPool .Names .SAME );
66
69
this .clusterService = clusterService ;
67
70
this .transportService = transportService ;
68
71
this .indexNameExpressionResolver = indexNameExpressionResolver ;
69
72
this .transportShardAction = actionName + "[s]" ;
70
- this .shardExecutor = shardExecutor ;
71
-
72
- transportService .registerRequestHandler (transportShardAction , ThreadPool .Names .SAME , shardRequest , new ShardTransportHandler ());
73
+ this .executor = transportService .getThreadPool ().executor (executor );
74
+ assert this .executor != EsExecutors .DIRECT_EXECUTOR_SERVICE : "O(#shards) work must always fork to an appropriate executor" ;
75
+
76
+ transportService .registerRequestHandler (
77
+ transportShardAction ,
78
+ executor ,
79
+ shardRequestReader ,
80
+ (request , channel , task ) -> ActionListener .completeWith (
81
+ new ChannelActionListener <>(channel ),
82
+ () -> shardOperation (request , task )
83
+ )
84
+ );
73
85
}
74
86
75
87
@ Override
76
88
protected void doExecute (Task task , Request request , ActionListener <Response > listener ) {
89
+ // workaround for https://github.com/elastic/elasticsearch/issues/97916 - TODO remove this when we can
90
+ executor .execute (ActionRunnable .wrap (listener , l -> doExecuteForked (task , request , listener )));
91
+ }
92
+
93
+ protected void doExecuteForked (Task task , Request request , ActionListener <Response > listener ) {
94
+ assert Transports .assertNotTransportThread ("O(#shards) work must always fork to an appropriate executor" );
77
95
new AsyncBroadcastAction (task , request , listener ).start ();
78
96
}
79
97
@@ -184,7 +202,7 @@ protected void sendShardRequest(DiscoveryNode node, ShardRequest shardRequest, A
184
202
node ,
185
203
transportShardAction ,
186
204
shardRequest ,
187
- new ActionListenerResponseHandler <>(listener , TransportBroadcastAction .this ::readShardResponse )
205
+ new ActionListenerResponseHandler <>(listener , TransportBroadcastAction .this ::readShardResponse , executor )
188
206
);
189
207
}
190
208
@@ -238,11 +256,8 @@ void onOperation(@Nullable ShardRouting shard, final ShardIterator shardIt, int
238
256
}
239
257
}
240
258
241
- protected AtomicReferenceArray <Object > shardsResponses () {
242
- return shardsResponses ;
243
- }
244
-
245
259
protected void finishHim () {
260
+ assert Transports .assertNotTransportThread ("O(#shards) work must always fork to an appropriate executor" );
246
261
ActionListener .completeWith (listener , () -> newResponse (request , shardsResponses , clusterState ));
247
262
}
248
263
@@ -269,24 +284,4 @@ void setFailure(ShardIterator shardIt, int shardIndex, Exception e) {
269
284
}
270
285
}
271
286
}
272
-
273
- class ShardTransportHandler implements TransportRequestHandler <ShardRequest > {
274
-
275
- @ Override
276
- public void messageReceived (ShardRequest request , TransportChannel channel , Task task ) throws Exception {
277
- asyncShardOperation (request , task , ActionListener .wrap (channel ::sendResponse , e -> {
278
- try {
279
- channel .sendResponse (e );
280
- } catch (Exception e1 ) {
281
- logger .warn (() -> format ("Failed to send error response for action [%s] and request [%s]" , actionName , request ), e1 );
282
- }
283
- }));
284
- }
285
- }
286
-
287
- private void asyncShardOperation (ShardRequest request , Task task , ActionListener <ShardResponse > listener ) {
288
- transportService .getThreadPool ()
289
- .executor (shardExecutor )
290
- .execute (ActionRunnable .supply (listener , () -> shardOperation (request , task )));
291
- }
292
287
}
0 commit comments