Cache the ChannelHandlerContext used in Http2StreamChannelBootstrap (#9382)

Motivation:

At the moment we lookup the ChannelHandlerContext used in Http2StreamChannelBootstrap each time the open(...) method is invoked. This is not needed and we can just cache it for later usage.

Modifications:

Cache ChannelHandlerContext in volatile field.

Result:

Speed up open(...) method implementation when called multiple times
This commit is contained in:
Norman Maurer 2019-07-18 10:20:34 +02:00
parent 2ef4b16138
commit 82ac20bec0

View File

@ -46,6 +46,9 @@ public final class Http2StreamChannelBootstrap {
private final Channel channel; private final Channel channel;
private volatile ChannelHandler handler; private volatile ChannelHandler handler;
// Cache the ChannelHandlerContext to speed up open(...) operations.
private volatile ChannelHandlerContext multiplexCtx;
public Http2StreamChannelBootstrap(Channel channel) { public Http2StreamChannelBootstrap(Channel channel) {
this.channel = requireNonNull(channel, "channel"); this.channel = requireNonNull(channel, "channel");
} }
@ -110,18 +113,8 @@ public final class Http2StreamChannelBootstrap {
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public Future<Http2StreamChannel> open(final Promise<Http2StreamChannel> promise) { public Future<Http2StreamChannel> open(final Promise<Http2StreamChannel> promise) {
ChannelHandlerContext ctx = channel.pipeline().context(Http2MultiplexCodec.class); try {
if (ctx == null) { ChannelHandlerContext ctx = findCtx();
ctx = channel.pipeline().context(Http2MultiplexHandler.class);
}
if (ctx == null) {
if (channel.isActive()) {
promise.setFailure(new IllegalStateException(StringUtil.simpleClassName(Http2MultiplexCodec.class) +
" must be in the ChannelPipeline of Channel " + channel));
} else {
promise.setFailure(new ClosedChannelException());
}
} else {
EventExecutor executor = ctx.executor(); EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
open0(ctx, promise); open0(ctx, promise);
@ -129,10 +122,36 @@ public final class Http2StreamChannelBootstrap {
final ChannelHandlerContext finalCtx = ctx; final ChannelHandlerContext finalCtx = ctx;
executor.execute(() -> open0(finalCtx, promise)); executor.execute(() -> open0(finalCtx, promise));
} }
} catch (Throwable cause) {
promise.setFailure(cause);
} }
return promise; return promise;
} }
private ChannelHandlerContext findCtx() throws ClosedChannelException {
// First try to use cached context and if this not work lets try to lookup the context.
ChannelHandlerContext ctx = this.multiplexCtx;
if (ctx != null && !ctx.isRemoved()) {
return ctx;
}
ChannelPipeline pipeline = channel.pipeline();
ctx = pipeline.context(Http2MultiplexCodec.class);
if (ctx == null) {
ctx = pipeline.context(Http2MultiplexHandler.class);
}
if (ctx == null) {
if (channel.isActive()) {
throw new IllegalStateException(StringUtil.simpleClassName(Http2MultiplexCodec.class) + " or "
+ StringUtil.simpleClassName(Http2MultiplexHandler.class)
+ " must be in the ChannelPipeline of Channel " + channel);
} else {
throw new ClosedChannelException();
}
}
this.multiplexCtx = ctx;
return ctx;
}
/** /**
* @deprecated should not be used directly. Use {@link #open()} or {@link #open(Promise)} * @deprecated should not be used directly. Use {@link #open()} or {@link #open(Promise)}
*/ */
@ -172,7 +191,7 @@ public final class Http2StreamChannelBootstrap {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void init(Channel channel) throws Exception { private void init(Channel channel) {
ChannelPipeline p = channel.pipeline(); ChannelPipeline p = channel.pipeline();
ChannelHandler handler = this.handler; ChannelHandler handler = this.handler;
if (handler != null) { if (handler != null) {