Skip to content

Commit

Permalink
Save expensive interface type checks (related JDK-8180450 and netty/n…
Browse files Browse the repository at this point in the history
  • Loading branch information
franz1981 authored and vietj committed Mar 1, 2023
1 parent da257ca commit 5eac2b0
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
34 changes: 19 additions & 15 deletions src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,24 @@ public HttpServerMetrics metrics() {
}

public void handleMessage(Object msg) {
if (msg instanceof HttpRequest) {
DefaultHttpRequest request = (DefaultHttpRequest) msg;
ContextInternal requestCtx = streamContextSupplier.get();
Http1xServerRequest req = new Http1xServerRequest(this, request, requestCtx);
requestInProgress = req;
if (responseInProgress != null) {
enqueueRequest(req);
return;
}
responseInProgress = requestInProgress;
req.handleBegin(writable);
Handler<HttpServerRequest> handler = request.decoderResult().isSuccess() ? requestHandler : invalidRequestHandler;
req.context.emit(req, handler);
} else if (msg == LastHttpContent.EMPTY_LAST_CONTENT) {
assert msg != null;
// fast-path first
if (msg == LastHttpContent.EMPTY_LAST_CONTENT) {
onEnd();
} else if (msg instanceof DefaultHttpRequest) {
// fast path type check vs concrete class
DefaultHttpRequest request = (DefaultHttpRequest) msg;
ContextInternal requestCtx = streamContextSupplier.get();
Http1xServerRequest req = new Http1xServerRequest(this, request, requestCtx);
requestInProgress = req;
if (responseInProgress != null) {
enqueueRequest(req);
return;
}
responseInProgress = requestInProgress;
req.handleBegin(writable);
Handler<HttpServerRequest> handler = request.decoderResult().isSuccess() ? requestHandler : invalidRequestHandler;
req.context.emit(req, handler);
} else {
handleOther(msg);
}
Expand All @@ -173,7 +176,8 @@ private void enqueueRequest(Http1xServerRequest req) {
}

private void handleOther(Object msg) {
if (msg instanceof HttpContent) {
// concrete type check first
if (msg instanceof DefaultHttpContent || msg instanceof HttpContent) {
onContent(msg);
} else if (msg instanceof WebSocketFrame) {
handleWsFrame((WebSocketFrame) msg);
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/vertx/core/http/impl/VertxHttpRequestDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,19 @@ protected HttpMessage createMessage(String[] initialLine) {
initialLine[1],
HeadersMultiMap.httpHeaders());
}

@Override
protected boolean isContentAlwaysEmpty(HttpMessage msg) {
if (msg == null) {
return false;
}
// we are forced to perform exact type check here because
// users can override createMessage with a DefaultHttpRequest implements HttpResponse
// and we have to enforce
// if (msg instance HttpResponse) return super.isContentAlwaysEmpty(msg)
if (msg.getClass() == DefaultHttpRequest.class) {
return false;
}
return super.isContentAlwaysEmpty(msg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.LastHttpContent;
import io.vertx.core.http.impl.headers.HeadersMultiMap;

/**
Expand All @@ -36,6 +41,29 @@ protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) {
}
}

@Override
public boolean acceptOutboundMessage(Object msg) throws Exception {
// fast-path singleton(s)
if (msg == Unpooled.EMPTY_BUFFER || msg == LastHttpContent.EMPTY_LAST_CONTENT) {
return true;
}
// fast-path exact class matches: we cannot use a (concrete) class type check
// here because the contract of HttpResponseEncoder::acceptOutboundMessage
// enforces msg to NOT implement HttpRequest and we don't know if users extends vertx/netty types to
// implement it.
final Class<?> msgClazz = msg.getClass();
if (msgClazz == AssembledFullHttpResponse.class ||
msgClazz == DefaultFullHttpResponse.class ||
msgClazz == AssembledHttpResponse.class ||
msgClazz == DefaultHttpContent.class ||
msgClazz == AssembledLastHttpContent.class ||
msgClazz == DefaultFileRegion.class) {
return true;
}
// Netty slow-path
return super.acceptOutboundMessage(msg);
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
super.handlerAdded(ctx);
Expand Down

0 comments on commit 5eac2b0

Please sign in to comment.