Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NettyProcessor documentation and update #43654

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,30 +100,53 @@ NativeImageConfigBuildItem build(
// Use small chunks to avoid a lot of wasted space. Default is 16mb * arenas (derived from core count)
// Since buffers are cached to threads, the malloc overhead is temporary anyway
.addNativeImageSystemProperty("io.netty.allocator.maxOrder", maxOrder)
.addRuntimeInitializedClass("io.netty.handler.ssl.JdkNpnApplicationProtocolNegotiator")
// Runtime initialize to respect io.netty.handler.ssl.conscrypt.useBufferAllocator
.addRuntimeInitializedClass("io.netty.handler.ssl.ConscryptAlpnSslEngine")
// Runtime initialize due to the use of tcnative in the static initializers?
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslEngine")
// Runtime initialize to respect run-time provided values of the following properties:
// - io.netty.handler.ssl.openssl.bioNonApplicationBufferSize
// - io.netty.handler.ssl.openssl.useTasks
// - jdk.tls.client.enableSessionTicketExtension
// - io.netty.handler.ssl.openssl.sessionCacheServer
// - io.netty.handler.ssl.openssl.sessionCacheClient
// - jdk.tls.ephemeralDHKeySize
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslContext")
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslClientContext")
// .addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslClientContext")
// Runtime initialize to respect run-time provided values of the following properties:
// - keystore.type
// - ssl.KeyManagerFactory.algorithm
// - ssl.TrustManagerFactory.algorithm
.addRuntimeInitializedClass("io.netty.handler.ssl.JdkSslServerContext")
.addRuntimeInitializedClass("io.netty.handler.ssl.JdkSslClientContext")
// .addRuntimeInitializedClass("io.netty.handler.ssl.JdkSslClientContext")
// Runtime initialize to prevent embedding SecureRandom instances in the native image
.addRuntimeInitializedClass("io.netty.handler.ssl.util.ThreadLocalInsecureRandom")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil$HexUtil")
.addRuntimeInitializedClass("io.netty.buffer.PooledByteBufAllocator")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufAllocator")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil")
// The default channel id uses the process id, it should not be cached in the native image.
// The default channel id uses the process id, it should not be cached in the native image. This way we
// also respect the run-time provided value of the io.netty.processId property, io.netty.machineId
// property is being hardcoded in setNettyMachineId method
.addRuntimeInitializedClass("io.netty.channel.DefaultChannelId")
// Disable leak detection by default, it can still be enabled via
// io.netty.util.ResourceLeakDetector.setLevel method
.addNativeImageSystemProperty("io.netty.leakDetection.level", "DISABLED");

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.handler.codec.http.HttpObjectEncoder")) {
builder
// Runtime initialize due to transitive use of the io.netty.util.internal.PlatformDependent class
// when initializing CRLF_BUF and ZERO_CRLF_CRLF_BUF
.addRuntimeInitializedClass("io.netty.handler.codec.http.HttpObjectEncoder")
.addRuntimeInitializedClass("io.netty.handler.codec.http.websocketx.extensions.compression.DeflateDecoder")
.addRuntimeInitializedClass("io.netty.handler.codec.http.websocketx.WebSocket00FrameEncoder")
.addRuntimeInitializedClass("io.netty.handler.codec.compression.ZstdOptions")
.addRuntimeInitializedClass("io.netty.handler.codec.compression.ZstdConstants");
// Brotli is an optional dependency
.addRuntimeInitializedClass("io.netty.handler.codec.http.websocketx.WebSocket00FrameEncoder");
// Zstd is an optional dependency, runtime initialize to avoid IllegalStateException when zstd is not
// available. This will result in a runtime ClassNotFoundException if the user tries to use zstd.
if (!QuarkusClassLoader.isClassPresentAtRuntime("com.github.luben.zstd.Zstd")) {
builder.addRuntimeInitializedClass("io.netty.handler.codec.compression.ZstdOptions")
.addRuntimeInitializedClass("io.netty.handler.codec.compression.ZstdConstants");
}
// Brotli is an optional dependency, we should only runtime initialize BrotliOptions to avoid
// IllegalStateException when brotli (e.g. com.aayushatharva.brotli4j.Brotli4jLoader) is not available.
// This will result in a runtime ClassNotFoundException if the user tries to use Brotli.
// Due to https://github.com/quarkusio/quarkus/issues/43662 we cannot do this yet though so we always enable
// runtime initialization of BrotliOptions if the class is present
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.handler.codec.compression.BrotliOptions")) {
builder.addRuntimeInitializedClass("io.netty.handler.codec.compression.BrotliOptions");
}
Expand All @@ -133,52 +156,116 @@ NativeImageConfigBuildItem build(

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.handler.codec.http2.Http2CodecUtil")) {
builder
// Runtime initialize due to the transitive use of the io.netty.util.internal.PlatformDependent
// class in the static initializers
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2CodecUtil")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ClientUpgradeCodec")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.DefaultHttp2FrameWriter")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ConnectionHandler");
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ConnectionHandler")
// Runtime initialize due to dependency on io.netty.handler.codec.http2.Http2CodecUtil
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ClientUpgradeCodec");
} else {
log.debug("Not registering Netty HTTP2 classes as they were not found");
}

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.unix.UnixChannel")) {
// Runtime initialize to avoid embedding quite a few Strings in the image heap
builder.addRuntimeInitializedClass("io.netty.channel.unix.Errors")
// Runtime initialize due to the use of AtomicIntegerFieldUpdater?
.addRuntimeInitializedClass("io.netty.channel.unix.FileDescriptor")
// Runtime initialize due to the use of Buffer.addressSize() in the static initializers
.addRuntimeInitializedClass("io.netty.channel.unix.IovArray")
// Runtime initialize due to the use of native methods in the static initializers?
.addRuntimeInitializedClass("io.netty.channel.unix.Limits");
} else {
log.debug("Not registering Netty native unix classes as they were not found");
}

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.epoll.EpollMode")) {
// Runtime initialize due to machine dependent native methods being called in static initializer and to
// respect the run-time provided value of io.netty.transport.noNative
builder.addRuntimeInitializedClass("io.netty.channel.epoll.Epoll")
// Runtime initialize due to machine dependent native methods being called in static initializer
.addRuntimeInitializedClass("io.netty.channel.epoll.EpollEventArray")
// Runtime initialize due to dependency on Epoll and to respect the run-time provided value of
// io.netty.channel.epoll.epollWaitThreshold
.addRuntimeInitializedClass("io.netty.channel.epoll.EpollEventLoop")
// Runtime initialize due to InetAddress fields, dependencies on native methods and to transitively
// respect a number of properties, e.g. java.nio.channels.spi.SelectorProvider
.addRuntimeInitializedClass("io.netty.channel.epoll.Native");
} else {
log.debug("Not registering Netty native epoll classes as they were not found");
}

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.kqueue.AcceptFilter")) {
// Runtime initialize due to machine dependent native methods being called in static initializer and to
// respect the run-time provided value of io.netty.transport.noNative
builder.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueue")
// Runtime initialize due to machine dependent native methods being called in static initializers
.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueueEventArray")
.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueueEventLoop")
.addRuntimeInitializedClass("io.netty.channel.kqueue.Native");
.addRuntimeInitializedClass("io.netty.channel.kqueue.Native")
// Runtime initialize due to dependency on Epoll and the use of AtomicIntegerFieldUpdater?
.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueueEventLoop");
} else {
log.debug("Not registering Netty native kqueue classes as they were not found");
}

// Runtime initialize due to platform dependent initialization and to respect the run-time provided value of the
// properties:
// - io.netty.maxDirectMemory
// - io.netty.uninitializedArrayAllocationThreshold
// - io.netty.noPreferDirect
// - io.netty.osClassifiers
// - io.netty.tmpdir
// - java.io.tmpdir
// - io.netty.bitMode
// - sun.arch.data.model
// - com.ibm.vm.bitmode
builder.addRuntimeReinitializedClass("io.netty.util.internal.PlatformDependent")
// Similarly for properties:
// - io.netty.noUnsafe
// - sun.misc.unsafe.memory.access
// - io.netty.tryUnsafe
// - org.jboss.netty.tryUnsafe
// - io.netty.tryReflectionSetAccessible
.addRuntimeReinitializedClass("io.netty.util.internal.PlatformDependent0");

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.buffer.UnpooledByteBufAllocator")) {
// Runtime initialize due to the use of the io.netty.util.internal.PlatformDependent class
builder.addRuntimeReinitializedClass("io.netty.buffer.UnpooledByteBufAllocator")
.addRuntimeReinitializedClass("io.netty.buffer.Unpooled")
// Runtime initialize due to dependency on io.netty.buffer.Unpooled
.addRuntimeReinitializedClass("io.netty.handler.codec.http.HttpObjectAggregator")
.addRuntimeReinitializedClass("io.netty.handler.codec.ReplayingDecoderByteBuf");
.addRuntimeReinitializedClass("io.netty.handler.codec.ReplayingDecoderByteBuf")
// Runtime initialize to avoid embedding quite a few Strings in the image heap
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil$HexUtil")
// Runtime initialize due to the use of the io.netty.util.internal.PlatformDependent class in the
// static initializers and to respect the run-time provided value of the following properties:
// - io.netty.allocator.directMemoryCacheAlignment
// - io.netty.allocator.pageSize
// - io.netty.allocator.maxOrder
// - io.netty.allocator.numHeapArenas
// - io.netty.allocator.numDirectArenas
// - io.netty.allocator.smallCacheSize
// - io.netty.allocator.normalCacheSize
// - io.netty.allocator.maxCachedBufferCapacity
// - io.netty.allocator.cacheTrimInterval
// - io.netty.allocation.cacheTrimIntervalMillis
// - io.netty.allocator.cacheTrimIntervalMillis
// - io.netty.allocator.useCacheForAllThreads
// - io.netty.allocator.maxCachedByteBuffersPerChunk
.addRuntimeInitializedClass("io.netty.buffer.PooledByteBufAllocator")
// Runtime initialize due to the use of ByteBufUtil.DEFAULT_ALLOCATOR in the static initializers
.addRuntimeInitializedClass("io.netty.buffer.ByteBufAllocator")
// Runtime initialize due to the use of the io.netty.util.internal.PlatformDependent class in the
// static initializers and to respect the run-time provided value of the following properties:
// - io.netty.allocator.type
// - io.netty.threadLocalDirectBufferSize
// - io.netty.maxThreadLocalCharBufferSize
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil");

if (QuarkusClassLoader
.isClassPresentAtRuntime("org.jboss.resteasy.reactive.client.impl.multipart.QuarkusMultipartFormUpload")) {
// Runtime initialize due to dependency on io.netty.buffer.Unpooled
builder.addRuntimeReinitializedClass(
"org.jboss.resteasy.reactive.client.impl.multipart.QuarkusMultipartFormUpload");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,61 @@
import io.netty.channel.ChannelHandlerContext;

public class HttpContentCompressorSubstitutions {
}

@TargetClass(className = "io.netty.handler.codec.compression.ZstdEncoder", onlyWith = IsZstdAbsent.class)
public static final class ZstdEncoderFactorySubstitution {

@Substitute
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
throw new UnsupportedOperationException();
}
@TargetClass(className = "io.netty.handler.codec.compression.ZstdEncoder", onlyWith = IsZstdAbsent.class)
final class Target_io_netty_handler_codec_compression_ZstdEncoder {

@Substitute
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) {
throw new UnsupportedOperationException();
}
@Substitute
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
throw new UnsupportedOperationException();
}

@Substitute
public void flush(final ChannelHandlerContext ctx) {
throw new UnsupportedOperationException();
}
@Substitute
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) {
throw new UnsupportedOperationException();
}

@Substitute
@TargetClass(className = "io.netty.handler.codec.compression.ZstdConstants", onlyWith = IsZstdAbsent.class)
public static final class ZstdConstants {
public void flush(final ChannelHandlerContext ctx) {
throw new UnsupportedOperationException();
}
}

// The constants make <clinit> calls to com.github.luben.zstd.Zstd so we cut links with that substitution.
@Substitute
@TargetClass(className = "io.netty.handler.codec.compression.ZstdConstants", onlyWith = IsZstdAbsent.class)
final class Target_io_netty_handler_codec_compression_ZstdConstants {

static final int DEFAULT_COMPRESSION_LEVEL = 0;
// The constants make <clinit> calls to com.github.luben.zstd.Zstd so we cut links with that substitution.

static final int MIN_COMPRESSION_LEVEL = 0;
static final int DEFAULT_COMPRESSION_LEVEL = 0;

static final int MAX_COMPRESSION_LEVEL = 0;
static final int MIN_COMPRESSION_LEVEL = 0;

static final int MAX_BLOCK_SIZE = 0;
static final int MAX_COMPRESSION_LEVEL = 0;

static final int DEFAULT_BLOCK_SIZE = 0;
}
static final int MAX_BLOCK_SIZE = 0;

public static class IsZstdAbsent implements BooleanSupplier {
static final int DEFAULT_BLOCK_SIZE = 0;
}

private boolean zstdAbsent;
class IsZstdAbsent implements BooleanSupplier {

public IsZstdAbsent() {
try {
Class.forName("com.github.luben.zstd.Zstd");
zstdAbsent = false;
} catch (Exception e) {
// It can be a classloading issue (the library is not available), or a native issue
// (the library for the current OS/arch is not available)
zstdAbsent = true;
}
}
private boolean zstdAbsent;

@Override
public boolean getAsBoolean() {
return zstdAbsent;
public IsZstdAbsent() {
try {
Class.forName("com.github.luben.zstd.Zstd");
zstdAbsent = false;
} catch (Exception e) {
// It can be a classloading issue (the library is not available), or a native issue
// (the library for the current OS/arch is not available)
zstdAbsent = true;
}
}

@Override
public boolean getAsBoolean() {
return zstdAbsent;
}
}
Loading