question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Upgrade to JC Tools 3.0 changes queue behavior when compiled natively on GraalVM.

See original GitHub issue

The upgrade to JC Tools 3.0 from 4.1.45 to 4.1.46 changes queue behavior when compiled natively on GraalVM.

For Netty 4.1.45 we used the following substitution in the Neo4j Java Driver

@TargetClass(className = "io.netty.channel.nio.NioEventLoop")
 final class Target_io_netty_channel_nio_NioEventLoop {

     @Substitute
     private static Queue<Runnable> newTaskQueue0(int maxPendingTasks) {
         return new LinkedBlockingDeque<>();
     }
 }

to force Netty to not use JC Tools Mscp queues. This is the same substitution that Quarkus uses (see https://github.com/quarkusio/quarkus/blob/0513ad94fd93f4ac377b796521a03dd3a52a156b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java#L313-L320) and which I proposed to include in Netty itself here (https://github.com/netty/netty/pull/9989).

This substitution is not enough anymore since Netty 4.1.46.

Netty 4.1.46 updated JC Tools to 3.0. When I downgrade this to 2.1.1 again, the substitution works as expected.

I have the suspicion that this change here https://github.com/JCTools/JCTools/commit/2ac1a663b3a378225ea1269e25b6383751954c4c triggers a different behavior in native image mode.

This can be mitigated by allowing unsafe, reflective field access to a couple of classes and fields of JC Tools in a reflection-config.json.

 {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerIndexField",
    "fields": [
      {"name": "producerIndex", "allowUnsafeAccess": true}
    ]
  },
  {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerLimitField",
    "fields": [
      {"name": "producerLimit", "allowUnsafeAccess": true}
    ]
  },
  {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueConsumerIndexField",
    "fields": [
      {"name": "consumerIndex", "allowUnsafeAccess": true}
    ]
  },
  {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
    "fields": [
      {"name": "producerIndex", "allowUnsafeAccess": true}
    ]
  },
  {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
    "fields": [
      {"name": "producerLimit", "allowUnsafeAccess": true}
    ]
  },
  {
    "name" : "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
    "fields": [
      {"name": "consumerIndex", "allowUnsafeAccess": true}
    ]
  }

If this is not done, any thing bootstrapping Netty will fail with something in this area:

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:290)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
	at java.lang.Class.ensureInitialized(DynamicHub.java:499)
	at io.netty.util.internal.PlatformDependent$Mpsc.newMpscQueue(PlatformDependent.java:934)
	at io.netty.util.internal.PlatformDependent.newMpscQueue(PlatformDependent.java:945)
	at io.netty.channel.nio.NioEventLoop.newTaskQueue0(NioEventLoop.java:279)
	at io.netty.channel.nio.NioEventLoop.newTaskQueue(NioEventLoop.java:150)
	at io.netty.channel.nio.NioEventLoop.<init>(NioEventLoop.java:138)
	at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:146)
	at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:37)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:84)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58)
	at io.netty.channel.MultithreadEventLoopGroup.<init>(MultithreadEventLoopGroup.java:52)
	at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:96)
	at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:91)
	at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:72)
	at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:52)
	at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:44)
	at ac.simons.netty.example.Client.main(Client.java:21)
Caused by: java.lang.RuntimeException: java.lang.NoSuchFieldException: producerIndex
	at io.netty.util.internal.shaded.org.jctools.util.UnsafeAccess.fieldOffset(UnsafeAccess.java:111)
	at io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields.<clinit>(BaseMpscLinkedArrayQueue.java:41)
	at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
	at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
	... 29 more
Caused by: java.lang.NoSuchFieldException: producerIndex
	at java.lang.Class.getDeclaredField(DynamicHub.java:2411)
	at io.netty.util.internal.shaded.org.jctools.util.UnsafeAccess.fieldOffset(UnsafeAccess.java:107)
	... 32 more

I have created the most simple reproducer I could: https://github.com/michael-simons/native-netty-timeserver-and-client Which is basically the vanilla server/client code from the Time server example of yours.

It can be compiled and run natively on the GraalVM. If you want to see the error, take this commit and update to anything >= 4.1.46 and stuff will fail.

The next commit contains the fixes.

Expected behavior or outcome

Nothing concrete at the moment: We at Neo4j can work around this, but it might have an impact on other projects that use Netty but are aiming for native compilation.

The substation mechanism seems brittle to say at least. Under the light of this experience here, I’d rather think about closing my pr but suggest picking up the suggested reflection config above for a future version of Netty. I personally don’t feel to well to refer to shaded things (which we shade again in our driver).

As this was discovered by the kind Quarkus team here https://github.com/quarkusio/quarkus/pull/10200, I’m also paging @gsmet and @cescoffier as they might run into the same issues with the Netty substitutions in Quarkus itself.

Maybe @nitsanw has an idea why the movement of the the static field initializations are now triggered early?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
cescoffiercommented, Jun 25, 2020

… we already using 4.1.49, so it needs to be updated.

0reactions
jvicancommented, Jun 9, 2021

FWIW it looks like -Dio.netty.noUnsafe is not necessary to get a performant Netty-based application compiled by GraalVM. I’ve been using this flag in production and recently discovered that I could remove it and Netty would behave just fine.

Read more comments on GitHub >

github_iconTop Results From Across the Web

GraalVM Updater
GraalVM Updater, gu , is a command-line tool for installing and managing optional GraalVM language runtimes and utilities. It is available in the...
Read more >
Release Notes - GraalVM Enterprise Edition
Improved JIT compilation isolation by using one isolate per the libgraal compiler thread. This avoids all GC interference between the compiler ...
Read more >
Untitled - Springer Link
Fundamentals of Physical Design and Query Compilation ... their application in different ML programming models and tools such as linear algebra scripts in....
Read more >
CO-DESIGNING SOFTWARE ABSTRACTION AND OPTIMISATION ...
C.5 Java code for the Levenberg-Marquardt Update SLAM kernel. . . 215 ... of compiling to native machine code against the expense of...
Read more >
(PDF) Canopy | Edison Gao - Academia.edu
Diagnosing these complex systems is a daunting challenge. Although many diagnostic tools exist, they are typically designed for a specific layer (eg, traceroute) ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found