2222import org .elasticsearch .common .util .concurrent .AbstractRunnable ;
2323import org .elasticsearch .common .util .concurrent .EsExecutors ;
2424import org .elasticsearch .common .util .concurrent .ThreadContext ;
25- import org .elasticsearch .core .Releasable ;
2625import org .elasticsearch .core .Releasables ;
2726import org .elasticsearch .core .TimeValue ;
2827import org .elasticsearch .threadpool .ThreadPool ;
@@ -87,21 +86,31 @@ void setSlowLogThreshold(TimeValue slowLogThreshold) {
8786 this .slowLogThresholdMs = slowLogThreshold .getMillis ();
8887 }
8988
89+ /**
90+ * @param message the transport message received, guaranteed to be closed by this method if it returns without exception.
91+ * Callers must ensure that {@code message} is closed if this method throws an exception but must not release
92+ * the message themselves otherwise
93+ */
9094 void inboundMessage (TcpChannel channel , InboundMessage message ) throws Exception {
9195 final long startTime = threadPool .rawRelativeTimeInMillis ();
9296 channel .getChannelStats ().markAccessed (startTime );
9397 TransportLogger .logInboundMessage (channel , message );
9498
9599 if (message .isPing ()) {
96- keepAlive .receiveKeepAlive (channel );
100+ keepAlive .receiveKeepAlive (channel ); // pings hold no resources, no need to close
97101 } else {
98- messageReceived (channel , message , startTime );
102+ messageReceived (channel , /* autocloses absent exception */ message , startTime );
99103 }
100104 }
101105
102106 // Empty stream constant to avoid instantiating a new stream for empty messages.
103107 private static final StreamInput EMPTY_STREAM_INPUT = new ByteBufferStreamInput (ByteBuffer .wrap (BytesRef .EMPTY_BYTES ));
104108
109+ /**
110+ * @param message the transport message received, guaranteed to be closed by this method if it returns without exception.
111+ * Callers must ensure that {@code message} is closed if this method throws an exception but must not release
112+ * the message themselves otherwise
113+ */
105114 private void messageReceived (TcpChannel channel , InboundMessage message , long startTime ) throws IOException {
106115 final InetSocketAddress remoteAddress = channel .getRemoteAddress ();
107116 final Header header = message .getHeader ();
@@ -115,14 +124,16 @@ private void messageReceived(TcpChannel channel, InboundMessage message, long st
115124 threadContext .setHeaders (header .getHeaders ());
116125 threadContext .putTransient ("_remote_address" , remoteAddress );
117126 if (header .isRequest ()) {
118- handleRequest (channel , message );
127+ handleRequest (channel , /* autocloses absent exception */ message );
119128 } else {
120129 // Responses do not support short circuiting currently
121130 assert message .isShortCircuit () == false ;
122131 responseHandler = findResponseHandler (header );
123132 // ignore if its null, the service logs it
124133 if (responseHandler != null ) {
125- executeResponseHandler (message , responseHandler , remoteAddress );
134+ executeResponseHandler ( /* autocloses absent exception */ message , responseHandler , remoteAddress );
135+ } else {
136+ message .close ();
126137 }
127138 }
128139 } finally {
@@ -135,6 +146,11 @@ private void messageReceived(TcpChannel channel, InboundMessage message, long st
135146 }
136147 }
137148
149+ /**
150+ * @param message the transport message received, guaranteed to be closed by this method if it returns without exception.
151+ * Callers must ensure that {@code message} is closed if this method throws an exception but must not release
152+ * the message themselves otherwise
153+ */
138154 private void executeResponseHandler (
139155 InboundMessage message ,
140156 TransportResponseHandler <?> responseHandler ,
@@ -145,13 +161,13 @@ private void executeResponseHandler(
145161 final StreamInput streamInput = namedWriteableStream (message .openOrGetStreamInput ());
146162 assert assertRemoteVersion (streamInput , header .getVersion ());
147163 if (header .isError ()) {
148- handlerResponseError (streamInput , message , responseHandler );
164+ handlerResponseError (streamInput , /* autocloses */ message , responseHandler );
149165 } else {
150- handleResponse (remoteAddress , streamInput , responseHandler , message );
166+ handleResponse (remoteAddress , streamInput , responseHandler , /* autocloses */ message );
151167 }
152168 } else {
153169 assert header .isError () == false ;
154- handleResponse (remoteAddress , EMPTY_STREAM_INPUT , responseHandler , message );
170+ handleResponse (remoteAddress , EMPTY_STREAM_INPUT , responseHandler , /* autocloses */ message );
155171 }
156172 }
157173
@@ -220,10 +236,15 @@ private void verifyResponseReadFully(Header header, TransportResponseHandler<?>
220236 }
221237 }
222238
239+ /**
240+ * @param message the transport message received, guaranteed to be closed by this method if it returns without exception.
241+ * Callers must ensure that {@code message} is closed if this method throws an exception but must not release
242+ * the message themselves otherwise
243+ */
223244 private <T extends TransportRequest > void handleRequest (TcpChannel channel , InboundMessage message ) throws IOException {
224245 final Header header = message .getHeader ();
225246 if (header .isHandshake ()) {
226- handleHandshakeRequest (channel , message );
247+ handleHandshakeRequest (channel , /* autocloses */ message );
227248 return ;
228249 }
229250
@@ -243,7 +264,7 @@ private <T extends TransportRequest> void handleRequest(TcpChannel channel, Inbo
243264 Releasables .assertOnce (message .takeBreakerReleaseControl ())
244265 );
245266
246- try {
267+ try ( message ) {
247268 messageListener .onRequestReceived (requestId , action );
248269 if (reg != null ) {
249270 reg .addRequestStats (header .getNetworkMessageSize () + TcpHeader .BYTES_REQUIRED_FOR_MESSAGE_SIZE );
@@ -331,6 +352,9 @@ public void onAfter() {
331352 }
332353 }
333354
355+ /**
356+ * @param message guaranteed to get closed by this method
357+ */
334358 private void handleHandshakeRequest (TcpChannel channel , InboundMessage message ) throws IOException {
335359 var header = message .getHeader ();
336360 assert header .actionName .equals (TransportHandshaker .HANDSHAKE_ACTION_NAME );
@@ -351,7 +375,7 @@ private void handleHandshakeRequest(TcpChannel channel, InboundMessage message)
351375 true ,
352376 Releasables .assertOnce (message .takeBreakerReleaseControl ())
353377 );
354- try {
378+ try ( message ) {
355379 handshaker .handleHandshake (transportChannel , requestId , stream );
356380 } catch (Exception e ) {
357381 logger .warn (
@@ -371,29 +395,30 @@ private static void sendErrorResponse(String actionName, TransportChannel transp
371395 }
372396 }
373397
398+ /**
399+ * @param message guaranteed to get closed by this method
400+ */
374401 private <T extends TransportResponse > void handleResponse (
375402 InetSocketAddress remoteAddress ,
376403 final StreamInput stream ,
377404 final TransportResponseHandler <T > handler ,
378- final InboundMessage inboundMessage
405+ final InboundMessage message
379406 ) {
380407 final var executor = handler .executor ();
381408 if (executor == EsExecutors .DIRECT_EXECUTOR_SERVICE ) {
382409 // no need to provide a buffer release here, we never escape the buffer when handling directly
383- doHandleResponse (handler , remoteAddress , stream , inboundMessage . getHeader (), () -> {} );
410+ doHandleResponse (handler , remoteAddress , stream , /* autocloses */ message );
384411 } else {
385- inboundMessage .mustIncRef ();
386412 // release buffer once we deserialize the message, but have a fail-safe in #onAfter below in case that didn't work out
387- final Releasable releaseBuffer = Releasables .releaseOnce (inboundMessage ::decRef );
388413 executor .execute (new ForkingResponseHandlerRunnable (handler , null ) {
389414 @ Override
390415 protected void doRun () {
391- doHandleResponse (handler , remoteAddress , stream , inboundMessage . getHeader (), releaseBuffer );
416+ doHandleResponse (handler , remoteAddress , stream , /* autocloses */ message );
392417 }
393418
394419 @ Override
395420 public void onAfter () {
396- Releasables . closeExpectNoException ( releaseBuffer );
421+ message . close ( );
397422 }
398423 });
399424 }
@@ -404,20 +429,19 @@ public void onAfter() {
404429 * @param handler response handler
405430 * @param remoteAddress remote address that the message was sent from
406431 * @param stream bytes stream for reading the message
407- * @param header message header
408- * @param releaseResponseBuffer releasable that will be released once the message has been read from the {@code stream}
432+ * @param inboundMessage inbound message, guaranteed to get closed by this method
409433 * @param <T> response message type
410434 */
411435 private <T extends TransportResponse > void doHandleResponse (
412436 TransportResponseHandler <T > handler ,
413437 InetSocketAddress remoteAddress ,
414438 final StreamInput stream ,
415- final Header header ,
416- Releasable releaseResponseBuffer
439+ InboundMessage inboundMessage
417440 ) {
418441 final T response ;
419- try (releaseResponseBuffer ) {
442+ try (inboundMessage ) {
420443 response = handler .read (stream );
444+ verifyResponseReadFully (inboundMessage .getHeader (), handler , stream );
421445 } catch (Exception e ) {
422446 final TransportException serializationException = new TransportSerializationException (
423447 "Failed to deserialize response from handler [" + handler + "]" ,
@@ -429,7 +453,6 @@ private <T extends TransportResponse> void doHandleResponse(
429453 return ;
430454 }
431455 try {
432- verifyResponseReadFully (header , handler , stream );
433456 handler .handleResponse (response );
434457 } catch (Exception e ) {
435458 doHandleException (handler , new ResponseHandlerFailureTransportException (e ));
@@ -438,9 +461,12 @@ private <T extends TransportResponse> void doHandleResponse(
438461 }
439462 }
440463
464+ /**
465+ * @param message guaranteed to get closed by this method
466+ */
441467 private void handlerResponseError (StreamInput stream , InboundMessage message , final TransportResponseHandler <?> handler ) {
442468 Exception error ;
443- try {
469+ try ( message ) {
444470 error = stream .readException ();
445471 verifyResponseReadFully (message .getHeader (), handler , stream );
446472 } catch (Exception e ) {
0 commit comments