22
22
import org .elasticsearch .common .util .concurrent .AbstractRunnable ;
23
23
import org .elasticsearch .common .util .concurrent .EsExecutors ;
24
24
import org .elasticsearch .common .util .concurrent .ThreadContext ;
25
- import org .elasticsearch .core .Releasable ;
26
25
import org .elasticsearch .core .Releasables ;
27
26
import org .elasticsearch .core .TimeValue ;
28
27
import org .elasticsearch .threadpool .ThreadPool ;
@@ -87,21 +86,31 @@ void setSlowLogThreshold(TimeValue slowLogThreshold) {
87
86
this .slowLogThresholdMs = slowLogThreshold .getMillis ();
88
87
}
89
88
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
+ */
90
94
void inboundMessage (TcpChannel channel , InboundMessage message ) throws Exception {
91
95
final long startTime = threadPool .rawRelativeTimeInMillis ();
92
96
channel .getChannelStats ().markAccessed (startTime );
93
97
TransportLogger .logInboundMessage (channel , message );
94
98
95
99
if (message .isPing ()) {
96
- keepAlive .receiveKeepAlive (channel );
100
+ keepAlive .receiveKeepAlive (channel ); // pings hold no resources, no need to close
97
101
} else {
98
- messageReceived (channel , message , startTime );
102
+ messageReceived (channel , /* autocloses absent exception */ message , startTime );
99
103
}
100
104
}
101
105
102
106
// Empty stream constant to avoid instantiating a new stream for empty messages.
103
107
private static final StreamInput EMPTY_STREAM_INPUT = new ByteBufferStreamInput (ByteBuffer .wrap (BytesRef .EMPTY_BYTES ));
104
108
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
+ */
105
114
private void messageReceived (TcpChannel channel , InboundMessage message , long startTime ) throws IOException {
106
115
final InetSocketAddress remoteAddress = channel .getRemoteAddress ();
107
116
final Header header = message .getHeader ();
@@ -115,14 +124,16 @@ private void messageReceived(TcpChannel channel, InboundMessage message, long st
115
124
threadContext .setHeaders (header .getHeaders ());
116
125
threadContext .putTransient ("_remote_address" , remoteAddress );
117
126
if (header .isRequest ()) {
118
- handleRequest (channel , message );
127
+ handleRequest (channel , /* autocloses absent exception */ message );
119
128
} else {
120
129
// Responses do not support short circuiting currently
121
130
assert message .isShortCircuit () == false ;
122
131
responseHandler = findResponseHandler (header );
123
132
// ignore if its null, the service logs it
124
133
if (responseHandler != null ) {
125
- executeResponseHandler (message , responseHandler , remoteAddress );
134
+ executeResponseHandler ( /* autocloses absent exception */ message , responseHandler , remoteAddress );
135
+ } else {
136
+ message .close ();
126
137
}
127
138
}
128
139
} finally {
@@ -135,6 +146,11 @@ private void messageReceived(TcpChannel channel, InboundMessage message, long st
135
146
}
136
147
}
137
148
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
+ */
138
154
private void executeResponseHandler (
139
155
InboundMessage message ,
140
156
TransportResponseHandler <?> responseHandler ,
@@ -145,13 +161,13 @@ private void executeResponseHandler(
145
161
final StreamInput streamInput = namedWriteableStream (message .openOrGetStreamInput ());
146
162
assert assertRemoteVersion (streamInput , header .getVersion ());
147
163
if (header .isError ()) {
148
- handlerResponseError (streamInput , message , responseHandler );
164
+ handlerResponseError (streamInput , /* autocloses */ message , responseHandler );
149
165
} else {
150
- handleResponse (remoteAddress , streamInput , responseHandler , message );
166
+ handleResponse (remoteAddress , streamInput , responseHandler , /* autocloses */ message );
151
167
}
152
168
} else {
153
169
assert header .isError () == false ;
154
- handleResponse (remoteAddress , EMPTY_STREAM_INPUT , responseHandler , message );
170
+ handleResponse (remoteAddress , EMPTY_STREAM_INPUT , responseHandler , /* autocloses */ message );
155
171
}
156
172
}
157
173
@@ -220,10 +236,15 @@ private void verifyResponseReadFully(Header header, TransportResponseHandler<?>
220
236
}
221
237
}
222
238
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
+ */
223
244
private <T extends TransportRequest > void handleRequest (TcpChannel channel , InboundMessage message ) throws IOException {
224
245
final Header header = message .getHeader ();
225
246
if (header .isHandshake ()) {
226
- handleHandshakeRequest (channel , message );
247
+ handleHandshakeRequest (channel , /* autocloses */ message );
227
248
return ;
228
249
}
229
250
@@ -243,7 +264,7 @@ private <T extends TransportRequest> void handleRequest(TcpChannel channel, Inbo
243
264
Releasables .assertOnce (message .takeBreakerReleaseControl ())
244
265
);
245
266
246
- try {
267
+ try ( message ) {
247
268
messageListener .onRequestReceived (requestId , action );
248
269
if (reg != null ) {
249
270
reg .addRequestStats (header .getNetworkMessageSize () + TcpHeader .BYTES_REQUIRED_FOR_MESSAGE_SIZE );
@@ -331,6 +352,9 @@ public void onAfter() {
331
352
}
332
353
}
333
354
355
+ /**
356
+ * @param message guaranteed to get closed by this method
357
+ */
334
358
private void handleHandshakeRequest (TcpChannel channel , InboundMessage message ) throws IOException {
335
359
var header = message .getHeader ();
336
360
assert header .actionName .equals (TransportHandshaker .HANDSHAKE_ACTION_NAME );
@@ -351,7 +375,7 @@ private void handleHandshakeRequest(TcpChannel channel, InboundMessage message)
351
375
true ,
352
376
Releasables .assertOnce (message .takeBreakerReleaseControl ())
353
377
);
354
- try {
378
+ try ( message ) {
355
379
handshaker .handleHandshake (transportChannel , requestId , stream );
356
380
} catch (Exception e ) {
357
381
logger .warn (
@@ -371,29 +395,30 @@ private static void sendErrorResponse(String actionName, TransportChannel transp
371
395
}
372
396
}
373
397
398
+ /**
399
+ * @param message guaranteed to get closed by this method
400
+ */
374
401
private <T extends TransportResponse > void handleResponse (
375
402
InetSocketAddress remoteAddress ,
376
403
final StreamInput stream ,
377
404
final TransportResponseHandler <T > handler ,
378
- final InboundMessage inboundMessage
405
+ final InboundMessage message
379
406
) {
380
407
final var executor = handler .executor ();
381
408
if (executor == EsExecutors .DIRECT_EXECUTOR_SERVICE ) {
382
409
// 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 );
384
411
} else {
385
- inboundMessage .mustIncRef ();
386
412
// 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 );
388
413
executor .execute (new ForkingResponseHandlerRunnable (handler , null ) {
389
414
@ Override
390
415
protected void doRun () {
391
- doHandleResponse (handler , remoteAddress , stream , inboundMessage . getHeader (), releaseBuffer );
416
+ doHandleResponse (handler , remoteAddress , stream , /* autocloses */ message );
392
417
}
393
418
394
419
@ Override
395
420
public void onAfter () {
396
- Releasables . closeExpectNoException ( releaseBuffer );
421
+ message . close ( );
397
422
}
398
423
});
399
424
}
@@ -404,20 +429,19 @@ public void onAfter() {
404
429
* @param handler response handler
405
430
* @param remoteAddress remote address that the message was sent from
406
431
* @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
409
433
* @param <T> response message type
410
434
*/
411
435
private <T extends TransportResponse > void doHandleResponse (
412
436
TransportResponseHandler <T > handler ,
413
437
InetSocketAddress remoteAddress ,
414
438
final StreamInput stream ,
415
- final Header header ,
416
- Releasable releaseResponseBuffer
439
+ InboundMessage inboundMessage
417
440
) {
418
441
final T response ;
419
- try (releaseResponseBuffer ) {
442
+ try (inboundMessage ) {
420
443
response = handler .read (stream );
444
+ verifyResponseReadFully (inboundMessage .getHeader (), handler , stream );
421
445
} catch (Exception e ) {
422
446
final TransportException serializationException = new TransportSerializationException (
423
447
"Failed to deserialize response from handler [" + handler + "]" ,
@@ -429,7 +453,6 @@ private <T extends TransportResponse> void doHandleResponse(
429
453
return ;
430
454
}
431
455
try {
432
- verifyResponseReadFully (header , handler , stream );
433
456
handler .handleResponse (response );
434
457
} catch (Exception e ) {
435
458
doHandleException (handler , new ResponseHandlerFailureTransportException (e ));
@@ -438,9 +461,12 @@ private <T extends TransportResponse> void doHandleResponse(
438
461
}
439
462
}
440
463
464
+ /**
465
+ * @param message guaranteed to get closed by this method
466
+ */
441
467
private void handlerResponseError (StreamInput stream , InboundMessage message , final TransportResponseHandler <?> handler ) {
442
468
Exception error ;
443
- try {
469
+ try ( message ) {
444
470
error = stream .readException ();
445
471
verifyResponseReadFully (message .getHeader (), handler , stream );
446
472
} catch (Exception e ) {
0 commit comments