Simplify and Optimize RestController Slightly (#45419) (#45485)

* Simplify the path iterator to generate less garbage
* `dispatchRequest` always terminates, adjust code accordingly
This commit is contained in:
Armin Braun 2019-08-13 10:43:30 +02:00 committed by GitHub
parent 488673f636
commit 00e4fba2fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 53 deletions

View File

@ -19,12 +19,9 @@
package org.elasticsearch.common.path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.BiFunction;
@ -352,40 +349,22 @@ public class PathTrie<T> {
* of parameters.
*/
public Iterator<T> retrieveAll(String path, Supplier<Map<String, String>> paramSupplier) {
return new PathTrieIterator<>(this, path, paramSupplier);
}
return new Iterator<T>() {
private static class PathTrieIterator<T> implements Iterator<T> {
private int mode;
private final List<TrieMatchingMode> modes;
private final Supplier<Map<String, String>> paramSupplier;
private final PathTrie<T> trie;
private final String path;
PathTrieIterator(PathTrie<T> trie, String path, Supplier<Map<String, String>> paramSupplier) {
this.path = path;
this.trie = trie;
this.paramSupplier = paramSupplier;
this.modes = new ArrayList<>(Arrays.asList(TrieMatchingMode.EXPLICIT_NODES_ONLY,
TrieMatchingMode.WILDCARD_ROOT_NODES_ALLOWED,
TrieMatchingMode.WILDCARD_LEAF_NODES_ALLOWED,
TrieMatchingMode.WILDCARD_NODES_ALLOWED));
assert TrieMatchingMode.values().length == 4 : "missing trie matching mode";
}
@Override
public boolean hasNext() {
return modes.isEmpty() == false;
}
@Override
public T next() {
if (modes.isEmpty()) {
throw new NoSuchElementException("called next() without validating hasNext()! no more modes available");
@Override
public boolean hasNext() {
return mode < TrieMatchingMode.values().length;
}
TrieMatchingMode mode = modes.remove(0);
Map<String, String> params = paramSupplier.get();
return trie.retrieve(path, params, mode);
}
@Override
public T next() {
if (hasNext() == false) {
throw new NoSuchElementException("called next() without validating hasNext()! no more modes available");
}
return retrieve(path, paramSupplier.get(), TrieMatchingMode.values()[mode++]);
}
};
}
}

View File

@ -48,7 +48,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@ -153,9 +152,8 @@ public class RestController implements HttpServerTransport.Dispatcher {
usageService.addRestHandler((BaseRestHandler) handler);
}
final RestHandler maybeWrappedHandler = handlerWrapper.apply(handler);
handlers.insertOrUpdate(path, new MethodHandlers(path, maybeWrappedHandler, method), (mHandlers, newMHandler) -> {
return mHandlers.addMethods(maybeWrappedHandler, method);
});
handlers.insertOrUpdate(path, new MethodHandlers(path, maybeWrappedHandler, method),
(mHandlers, newMHandler) -> mHandlers.addMethods(maybeWrappedHandler, method));
}
@Override
@ -198,22 +196,19 @@ public class RestController implements HttpServerTransport.Dispatcher {
}
}
/**
* Dispatch the request, if possible, returning true if a response was sent or false otherwise.
*/
private boolean dispatchRequest(RestRequest request, RestChannel channel, RestHandler handler) throws Exception {
private void dispatchRequest(RestRequest request, RestChannel channel, RestHandler handler) throws Exception {
final int contentLength = request.content().length();
if (contentLength > 0) {
final XContentType xContentType = request.getXContentType();
if (xContentType == null) {
sendContentTypeErrorMessage(request.getAllHeaderValues("Content-Type"), channel);
return true;
return;
}
if (handler.supportsContentStream() && xContentType != XContentType.JSON && xContentType != XContentType.SMILE) {
channel.sendResponse(BytesRestResponse.createSimpleErrorResponse(channel, RestStatus.NOT_ACCEPTABLE,
"Content-Type [" + xContentType + "] does not support stream parsing. Use JSON or SMILE instead"));
return;
}
if (handler.supportsContentStream() && xContentType != XContentType.JSON && xContentType != XContentType.SMILE) {
channel.sendResponse(BytesRestResponse.createSimpleErrorResponse(channel, RestStatus.NOT_ACCEPTABLE,
"Content-Type [" + xContentType + "] does not support stream parsing. Use JSON or SMILE instead"));
return true;
}
}
RestChannel responseChannel = channel;
try {
@ -228,7 +223,6 @@ public class RestController implements HttpServerTransport.Dispatcher {
} catch (Exception e) {
responseChannel.sendResponse(new BytesRestResponse(responseChannel, e));
}
return true;
}
private boolean handleNoHandlerFound(String rawPath, RestRequest.Method method, String uri, RestChannel channel) {
@ -297,7 +291,8 @@ public class RestController implements HttpServerTransport.Dispatcher {
if (handleNoHandlerFound(rawPath, requestMethod, uri, channel)) {
return;
}
} else if (dispatchRequest(request, channel, handler)) {
} else {
dispatchRequest(request, channel, handler);
return;
}
}
@ -402,8 +397,11 @@ public class RestController implements HttpServerTransport.Dispatcher {
private Set<RestRequest.Method> getValidHandlerMethodSet(String rawPath) {
Set<RestRequest.Method> validMethods = new HashSet<>();
Iterator<MethodHandlers> allHandlers = getAllHandlers(null, rawPath);
for (Iterator<MethodHandlers> it = allHandlers; it.hasNext(); ) {
Optional.ofNullable(it.next()).map(mh -> validMethods.addAll(mh.getValidMethods()));
while (allHandlers.hasNext()) {
final MethodHandlers methodHandlers = allHandlers.next();
if (methodHandlers != null) {
validMethods.addAll(methodHandlers.getValidMethods());
}
}
return validMethods;
}