Skip to content

Commit 2e21a17

Browse files
Release cluster state bytes earlier in PublicationTransportHandler
The cluster state publication can be quite large, especially when initially joining a cluster. By not leaving the forking to the transport layer we can release the network buffer before actually processing it which can save up to O(100M) of heap in some situations and improves stability quite a bit for situations where small nodes join clusters with large existing states.
1 parent 75f8e4a commit 2e21a17

File tree

1 file changed

+40
-7
lines changed

1 file changed

+40
-7
lines changed

server/src/main/java/org/elasticsearch/cluster/coordination/PublicationTransportHandler.java

+40-7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.elasticsearch.transport.Transport;
4646
import org.elasticsearch.transport.TransportException;
4747
import org.elasticsearch.transport.TransportRequestOptions;
48+
import org.elasticsearch.transport.TransportResponseHandler;
4849
import org.elasticsearch.transport.TransportService;
4950

5051
import java.io.IOException;
@@ -106,13 +107,36 @@ public PublicationTransportHandler(
106107
this.namedWriteableRegistry = namedWriteableRegistry;
107108
this.handlePublishRequest = handlePublishRequest;
108109

110+
var generic = transportService.getThreadPool().generic();
109111
transportService.registerRequestHandler(
110112
PUBLISH_STATE_ACTION_NAME,
111-
transportService.getThreadPool().generic(),
113+
TransportResponseHandler.TRANSPORT_WORKER,
112114
false,
113115
false,
114116
BytesTransportRequest::new,
115-
(request, channel, task) -> this.handleIncomingPublishRequest(request, new ChannelActionListener<>(channel))
117+
(req, channel, task) -> {
118+
req.mustIncRef();
119+
generic.execute(new ActionRunnable<>(new ChannelActionListener<PublishWithJoinResponse>(channel)) {
120+
121+
private BytesTransportRequest request = req;
122+
123+
@Override
124+
protected void doRun() throws IOException {
125+
var request = this.request;
126+
this.request = null;
127+
handleIncomingPublishRequest(request, listener);
128+
}
129+
130+
@Override
131+
public void onFailure(Exception e) {
132+
if (request != null) {
133+
request.decRef();
134+
this.request = null;
135+
}
136+
super.onFailure(e);
137+
}
138+
});
139+
}
116140
);
117141
}
118142

@@ -129,10 +153,12 @@ private void handleIncomingPublishRequest(
129153
BytesTransportRequest request,
130154
ActionListener<PublishWithJoinResponse> publishResponseListener
131155
) throws IOException {
132-
assert ThreadPool.assertCurrentThreadPool(GENERIC);
133-
final Compressor compressor = CompressorFactory.compressor(request.bytes());
134-
StreamInput in = request.bytes().streamInput();
156+
var bytes = request.bytes();
157+
StreamInput in = bytes.streamInput();
135158
try {
159+
assert ThreadPool.assertCurrentThreadPool(GENERIC);
160+
final Compressor compressor = CompressorFactory.compressor(bytes);
161+
final int requestLength = bytes.length();
136162
if (compressor != null) {
137163
in = compressor.threadLocalStreamInput(in);
138164
}
@@ -150,8 +176,10 @@ private void handleIncomingPublishRequest(
150176
assert false : e;
151177
throw e;
152178
}
179+
request.decRef();
180+
request = null;
153181
fullClusterStateReceivedCount.incrementAndGet();
154-
logger.debug("received full cluster state version [{}] with size [{}]", incomingState.version(), request.bytes().length());
182+
logger.debug("received full cluster state version [{}] with size [{}]", incomingState.version(), requestLength);
155183
acceptState(incomingState, publishResponseListener.map(response -> {
156184
lastSeenClusterState.set(incomingState);
157185
return response;
@@ -164,12 +192,14 @@ private void handleIncomingPublishRequest(
164192
throw new IncompatibleClusterStateVersionException("have no local cluster state");
165193
} else {
166194
final ClusterState incomingState = deserializeAndApplyDiff(request, in, lastSeen);
195+
request.decRef();
196+
request = null;
167197
compatibleClusterStateDiffReceivedCount.incrementAndGet();
168198
logger.debug(
169199
"received diff cluster state version [{}] with uuid [{}], diff size [{}]",
170200
incomingState.version(),
171201
incomingState.stateUUID(),
172-
request.bytes().length()
202+
requestLength
173203
);
174204
acceptState(incomingState, publishResponseListener.map(response -> {
175205
lastSeenClusterState.compareAndSet(lastSeen, incomingState);
@@ -178,6 +208,9 @@ private void handleIncomingPublishRequest(
178208
}
179209
}
180210
} finally {
211+
if (request != null) {
212+
request.decRef();
213+
}
181214
IOUtils.close(in);
182215
}
183216
}

0 commit comments

Comments
 (0)