13
13
import org .elasticsearch .action .ActionListener ;
14
14
import org .elasticsearch .action .ActionRequestValidationException ;
15
15
import org .elasticsearch .action .ActionResponse ;
16
+ import org .elasticsearch .action .ActionRunnable ;
16
17
import org .elasticsearch .action .ActionType ;
18
+ import org .elasticsearch .action .SingleResultDeduplicator ;
17
19
import org .elasticsearch .action .admin .cluster .node .stats .NodesStatsRequestParameters .Metric ;
18
20
import org .elasticsearch .action .support .ActionFilters ;
21
+ import org .elasticsearch .action .support .SubscribableListener ;
19
22
import org .elasticsearch .action .support .master .MasterNodeReadRequest ;
20
23
import org .elasticsearch .action .support .master .TransportMasterNodeReadAction ;
21
24
import org .elasticsearch .cluster .ClusterState ;
28
31
import org .elasticsearch .cluster .service .ClusterService ;
29
32
import org .elasticsearch .common .io .stream .StreamInput ;
30
33
import org .elasticsearch .common .io .stream .StreamOutput ;
34
+ import org .elasticsearch .common .util .concurrent .EsExecutors ;
31
35
import org .elasticsearch .core .Nullable ;
32
36
import org .elasticsearch .core .TimeValue ;
33
37
import org .elasticsearch .features .FeatureService ;
@@ -47,7 +51,7 @@ public class TransportGetAllocationStatsAction extends TransportMasterNodeReadAc
47
51
48
52
public static final ActionType <TransportGetAllocationStatsAction .Response > TYPE = new ActionType <>("cluster:monitor/allocation/stats" );
49
53
50
- private final AllocationStatsService allocationStatsService ;
54
+ private final SingleResultDeduplicator < Map < String , NodeAllocationStats >> allocationStatsSupplier ;
51
55
private final DiskThresholdSettings diskThresholdSettings ;
52
56
private final FeatureService featureService ;
53
57
@@ -70,9 +74,15 @@ public TransportGetAllocationStatsAction(
70
74
TransportGetAllocationStatsAction .Request ::new ,
71
75
indexNameExpressionResolver ,
72
76
TransportGetAllocationStatsAction .Response ::new ,
73
- threadPool .executor (ThreadPool .Names .MANAGEMENT )
77
+ // DIRECT is ok here because we fork the allocation stats computation onto a MANAGEMENT thread if needed, or else we return
78
+ // very cheaply.
79
+ EsExecutors .DIRECT_EXECUTOR_SERVICE
80
+ );
81
+ final var managementExecutor = threadPool .executor (ThreadPool .Names .MANAGEMENT );
82
+ this .allocationStatsSupplier = new SingleResultDeduplicator <>(
83
+ threadPool .getThreadContext (),
84
+ l -> managementExecutor .execute (ActionRunnable .supply (l , allocationStatsService ::stats ))
74
85
);
75
- this .allocationStatsService = allocationStatsService ;
76
86
this .diskThresholdSettings = new DiskThresholdSettings (clusterService .getSettings (), clusterService .getClusterSettings ());
77
87
this .featureService = featureService ;
78
88
}
@@ -89,15 +99,21 @@ protected void doExecute(Task task, Request request, ActionListener<Response> li
89
99
90
100
@ Override
91
101
protected void masterOperation (Task task , Request request , ClusterState state , ActionListener <Response > listener ) throws Exception {
92
- listener .onResponse (
93
- new Response (
94
- request .metrics ().contains (Metric .ALLOCATIONS ) ? allocationStatsService .stats () : Map .of (),
102
+ // NB we are still on a transport thread here - if adding more functionality here make sure to fork to a different pool
103
+
104
+ final SubscribableListener <Map <String , NodeAllocationStats >> allocationStatsStep = request .metrics ().contains (Metric .ALLOCATIONS )
105
+ ? SubscribableListener .newForked (allocationStatsSupplier ::execute )
106
+ : SubscribableListener .newSucceeded (Map .of ());
107
+
108
+ allocationStatsStep .andThenApply (
109
+ allocationStats -> new Response (
110
+ allocationStats ,
95
111
request .metrics ().contains (Metric .FS )
96
112
&& featureService .clusterHasFeature (clusterService .state (), AllocationStatsFeatures .INCLUDE_DISK_THRESHOLD_SETTINGS )
97
113
? diskThresholdSettings
98
114
: null
99
115
)
100
- );
116
+ ). addListener ( listener ) ;
101
117
}
102
118
103
119
@ Override
0 commit comments