Skip to content

Commit 67ccef9

Browse files
Lazily initialize TransportActionStats in RequestHandlerRegistry (#117435) (#118381)
Same as #114107 but for the transport side. We are consuming more than 0.5M for these stat instances and a large fraction if not the majority will go unused in many use-cases, given how expensive stats are in terms of volatile operations the overhead of an added `getAcquire` is trivial in the absence of writes. Outside of reducing the prod footprint this is also kind of nice in x-pack internal cluster tests in particular where it saves quite a bit of heap. Co-authored-by: Dimitris Rempapis <[email protected]>
1 parent 1c81918 commit 67ccef9

File tree

4 files changed

+47
-6
lines changed

4 files changed

+47
-6
lines changed

server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
import org.elasticsearch.node.NodeValidationException;
5151
import org.elasticsearch.plugins.PluginBundle;
5252
import org.elasticsearch.plugins.PluginsLoader;
53+
import org.elasticsearch.rest.MethodHandlers;
54+
import org.elasticsearch.transport.RequestHandlerRegistry;
5355

5456
import java.io.IOException;
5557
import java.io.InputStream;
@@ -209,7 +211,11 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
209211
SubscribableListener.class,
210212
RunOnce.class,
211213
// We eagerly initialize to work around log4j permissions & JDK-8309727
212-
VectorUtil.class
214+
VectorUtil.class,
215+
// RequestHandlerRegistry and MethodHandlers classes do nontrivial static initialization which should always succeed but load
216+
// it now (before SM) to be sure
217+
RequestHandlerRegistry.class,
218+
MethodHandlers.class
213219
);
214220

215221
// load the plugin Java modules and layers now for use in entitlements

server/src/main/java/org/elasticsearch/rest/MethodHandlers.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222
/**
2323
* Encapsulate multiple handlers for the same path, allowing different handlers for different HTTP verbs and versions.
2424
*/
25-
final class MethodHandlers {
25+
public final class MethodHandlers {
2626

2727
private final String path;
2828
private final Map<RestRequest.Method, Map<RestApiVersion, RestHandler>> methodHandlers;
2929

3030
@SuppressWarnings("unused") // only accessed via #STATS_TRACKER_HANDLE, lazy initialized because instances consume non-trivial heap
31-
private volatile HttpRouteStatsTracker statsTracker;
31+
private HttpRouteStatsTracker statsTracker;
3232

3333
private static final VarHandle STATS_TRACKER_HANDLE;
3434

server/src/main/java/org/elasticsearch/transport/RequestHandlerRegistry.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import org.elasticsearch.tasks.TaskManager;
1919

2020
import java.io.IOException;
21+
import java.lang.invoke.MethodHandles;
22+
import java.lang.invoke.VarHandle;
2123
import java.util.concurrent.Executor;
2224

2325
import static org.elasticsearch.core.Releasables.assertOnce;
@@ -31,7 +33,19 @@ public class RequestHandlerRegistry<Request extends TransportRequest> implements
3133
private final Executor executor;
3234
private final TaskManager taskManager;
3335
private final Writeable.Reader<Request> requestReader;
34-
private final TransportActionStatsTracker statsTracker = new TransportActionStatsTracker();
36+
@SuppressWarnings("unused") // only accessed via #STATS_TRACKER_HANDLE, lazy initialized because instances consume non-trivial heap
37+
private TransportActionStatsTracker statsTracker;
38+
39+
private static final VarHandle STATS_TRACKER_HANDLE;
40+
41+
static {
42+
try {
43+
STATS_TRACKER_HANDLE = MethodHandles.lookup()
44+
.findVarHandle(RequestHandlerRegistry.class, "statsTracker", TransportActionStatsTracker.class);
45+
} catch (Exception e) {
46+
throw new ExceptionInInitializerError(e);
47+
}
48+
}
3549

3650
public RequestHandlerRegistry(
3751
String action,
@@ -113,15 +127,34 @@ public static <R extends TransportRequest> RequestHandlerRegistry<R> replaceHand
113127
}
114128

115129
public void addRequestStats(int messageSize) {
116-
statsTracker.addRequestStats(messageSize);
130+
statsTracker().addRequestStats(messageSize);
117131
}
118132

119133
@Override
120134
public void addResponseStats(int messageSize) {
121-
statsTracker.addResponseStats(messageSize);
135+
statsTracker().addResponseStats(messageSize);
122136
}
123137

124138
public TransportActionStats getStats() {
139+
var statsTracker = existingStatsTracker();
140+
if (statsTracker == null) {
141+
return TransportActionStats.EMPTY;
142+
}
125143
return statsTracker.getStats();
126144
}
145+
146+
private TransportActionStatsTracker statsTracker() {
147+
var tracker = existingStatsTracker();
148+
if (tracker == null) {
149+
var newTracker = new TransportActionStatsTracker();
150+
if ((tracker = (TransportActionStatsTracker) STATS_TRACKER_HANDLE.compareAndExchange(this, null, newTracker)) == null) {
151+
tracker = newTracker;
152+
}
153+
}
154+
return tracker;
155+
}
156+
157+
private TransportActionStatsTracker existingStatsTracker() {
158+
return (TransportActionStatsTracker) STATS_TRACKER_HANDLE.getAcquire(this);
159+
}
127160
}

server/src/main/java/org/elasticsearch/transport/TransportActionStats.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public record TransportActionStats(
2727
long[] responseSizeHistogram
2828
) implements Writeable, ToXContentObject {
2929

30+
public static final TransportActionStats EMPTY = new TransportActionStats(0, 0, new long[0], 0, 0, new long[0]);
31+
3032
public TransportActionStats(StreamInput in) throws IOException {
3133
this(in.readVLong(), in.readVLong(), in.readVLongArray(), in.readVLong(), in.readVLong(), in.readVLongArray());
3234
}

0 commit comments

Comments
 (0)