Skip to content

Commit 0c089d6

Browse files
original-brownbearjkakavas
authored andcommitted
Stop Recreating Wrapped Handlers in RestController (#44964)
* We shouldn't be recreating wrapped REST handlers over and over for every request. We only use this hook in x-pack and the wrapper there does not have any per request state. This is inefficient and could lead to some very unexpected memory behavior => I made the logic create the wrapper on handler registration and adjusted the x-pack wrapper implementation to correctly forward the circuit breaker and content stream flags
1 parent 73bbb7f commit 0c089d6

File tree

3 files changed

+29
-17
lines changed

3 files changed

+29
-17
lines changed

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ public void registerHandler(RestRequest.Method method, String path, RestHandler
151151
if (handler instanceof BaseRestHandler) {
152152
usageService.addRestHandler((BaseRestHandler) handler);
153153
}
154-
handlers.insertOrUpdate(path, new MethodHandlers(path, handler, method), (mHandlers, newMHandler) -> {
155-
return mHandlers.addMethods(handler, method);
154+
final RestHandler maybeWrappedHandler = handlerWrapper.apply(handler);
155+
handlers.insertOrUpdate(path, new MethodHandlers(path, maybeWrappedHandler, method), (mHandlers, newMHandler) -> {
156+
return mHandlers.addMethods(maybeWrappedHandler, method);
156157
});
157158
}
158159

@@ -235,7 +236,7 @@ boolean dispatchRequest(final RestRequest request, final RestChannel channel, fi
235236
// iff we could reserve bytes for the request we need to send the response also over this channel
236237
responseChannel = new ResourceHandlingHttpChannel(channel, circuitBreakerService, contentLength);
237238

238-
final RestHandler wrappedHandler = mHandler.map(h -> handlerWrapper.apply(h)).get();
239+
final RestHandler wrappedHandler = mHandler.get();
239240
wrappedHandler.handleRequest(request, responseChannel, client);
240241
requestHandled = true;
241242
} catch (Exception e) {

server/src/test/java/org/elasticsearch/rest/RestControllerTests.java

+13-12
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
import java.util.Set;
5959
import java.util.concurrent.atomic.AtomicBoolean;
6060
import java.util.concurrent.atomic.AtomicReference;
61-
import java.util.function.UnaryOperator;
6261

6362
import static org.hamcrest.Matchers.containsString;
6463
import static org.hamcrest.Matchers.equalTo;
@@ -81,7 +80,6 @@ public class RestControllerTests extends ESTestCase {
8180

8281
@Before
8382
public void setup() {
84-
Settings settings = Settings.EMPTY;
8583
circuitBreakerService = new HierarchyCircuitBreakerService(
8684
Settings.builder()
8785
.put(HierarchyCircuitBreakerService.IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_LIMIT_SETTING.getKey(), BREAKER_LIMIT)
@@ -206,16 +204,19 @@ public void testRegisterWithDeprecatedHandler() {
206204
public void testRestHandlerWrapper() throws Exception {
207205
AtomicBoolean handlerCalled = new AtomicBoolean(false);
208206
AtomicBoolean wrapperCalled = new AtomicBoolean(false);
209-
RestHandler handler = (RestRequest request, RestChannel channel, NodeClient client) -> {
210-
handlerCalled.set(true);
211-
};
212-
UnaryOperator<RestHandler> wrapper = h -> {
213-
assertSame(handler, h);
214-
return (RestRequest request, RestChannel channel, NodeClient client) -> wrapperCalled.set(true);
215-
};
216-
final RestController restController = new RestController(Collections.emptySet(), wrapper, null,
217-
circuitBreakerService, usageService);
218-
restController.dispatchRequest(new FakeRestRequest.Builder(xContentRegistry()).build(), null, null, Optional.of(handler));
207+
final RestHandler handler = (RestRequest request, RestChannel channel, NodeClient client) -> handlerCalled.set(true);
208+
final HttpServerTransport httpServerTransport = new TestHttpServerTransport();
209+
final RestController restController =
210+
new RestController(Collections.emptySet(),
211+
h -> {
212+
assertSame(handler, h);
213+
return (RestRequest request, RestChannel channel, NodeClient client) -> wrapperCalled.set(true);
214+
}, null, circuitBreakerService, usageService);
215+
restController.registerHandler(RestRequest.Method.GET, "/wrapped", handler);
216+
RestRequest request = testRestRequest("/wrapped", "{}", XContentType.JSON);
217+
AssertingChannel channel = new AssertingChannel(request, true, RestStatus.BAD_REQUEST);
218+
restController.dispatchRequest(request, channel, new ThreadContext(Settings.EMPTY));
219+
httpServerTransport.start();
219220
assertTrue(wrapperCalled.get());
220221
assertFalse(handlerCalled.get());
221222
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
*/
66
package org.elasticsearch.xpack.security.rest;
77

8-
import org.apache.logging.log4j.Logger;
98
import org.apache.logging.log4j.LogManager;
9+
import org.apache.logging.log4j.Logger;
1010
import org.apache.logging.log4j.message.ParameterizedMessage;
1111
import org.apache.logging.log4j.util.Supplier;
1212
import org.elasticsearch.action.ActionListener;
@@ -70,7 +70,17 @@ public void handleRequest(RestRequest request, RestChannel channel, NodeClient c
7070
}
7171
}
7272

73-
RestRequest maybeWrapRestRequest(RestRequest restRequest) throws IOException {
73+
@Override
74+
public boolean canTripCircuitBreaker() {
75+
return restHandler.canTripCircuitBreaker();
76+
}
77+
78+
@Override
79+
public boolean supportsContentStream() {
80+
return restHandler.supportsContentStream();
81+
}
82+
83+
private RestRequest maybeWrapRestRequest(RestRequest restRequest) throws IOException {
7484
if (restHandler instanceof RestRequestFilter) {
7585
return ((RestRequestFilter)restHandler).getFilteredRequest(restRequest);
7686
}

0 commit comments

Comments
 (0)