1

I have an error using a Maven plugin with Java 19 specifically. Java 18 is working fine. How could I solve this issue?

I'm running within a Docker container on Centos 7.9.2009. When testing within the same container on Ubuntu 20.0 - kernel 5.15.0-52-generic, it works without issue.

The stacktrace is the following.

Caused by: java.io.IOException: Function not implemented
Oct 28 12:12:49     at sun.nio.ch.FileChannelImpl.transferFrom0 (Native Method)
Oct 28 12:12:49     at sun.nio.ch.FileChannelImpl.transferFromDirectlyInternal (FileChannelImpl.java:804)
Oct 28 12:12:49     at sun.nio.ch.FileChannelImpl.transferFromDirectly (FileChannelImpl.java:833)
Oct 28 12:12:49     at sun.nio.ch.FileChannelImpl.transferFrom (FileChannelImpl.java:935)
Oct 28 12:12:49     at org.codehaus.plexus.util.FileUtils.doCopyFile (FileUtils.java:1077)
Oct 28 12:12:49     at org.codehaus.plexus.util.FileUtils.copyFile (FileUtils.java:1049)

Versions used

Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Java version: 19, vendor: Eclipse Adoptium, runtime: /opt/java/openjdk
OS name: "linux", version: "3.10.0-1160.76.1.el7.x86_64", arch: "amd64", family: "unix"
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Nicolas Henneaux
  • 11,507
  • 11
  • 57
  • 82
  • 3
    It's possible that the implementation of that method requires a system call that isn't present on the CentOS kernel. Since containers don't bring their own kernel with them, they depend on functionality being present in the host kernel. Is `3.10.0` the kernel version that's running on CentOS? If so, that kernel would be ~11 years old (with plenty of patches applied, I'm sure), so it wouldn't be a surprise if something is missing. – Joachim Sauer Oct 28 '22 at 12:48
  • Indeed `3.10.0-1160.76.1.el7.x86_64` is the CentOS kernel. Is it expected the JVM fails on that or it should fallback to another method? – Nicolas Henneaux Oct 28 '22 at 13:01
  • 2
    I found no information what the minimum expected kernel is for OpenJDK 19 on Linux, but it's possible that there is an alternate implementation, but your problem suggests that it's not in use (or at least not automatically). – Joachim Sauer Oct 28 '22 at 14:51

1 Answers1

6

I was curious so I dug into the matter. It seems my original comment is right: your kernel version is too early for this specific function:

  • FileChannelImpl.transferFrom0 is implemented here
  • it first checks if my_copy_file_range_func is non-null and returns IOS_UNSUPPORTED otherwise (which is probably what happens).
  • my_copy_file_range_func is apparently initialized here by looking for the symbol copy_file_range.
  • According to this man page that system call was added to the Linux kernel 4.5, but is emulated in userspace by glibc since 2.27.

Linux 4.5 was released in March 2016 and glibc 2.27 in February 2018.

Since the libc is in fact provided by the container, when it's used (note that a musl-based container like Alpine might have other requirements) it should be sufficient to make sure that your container contains a glibc version that's newer than 2.27.

Note that a userspace emulation of that function will not provide the zero-copy efficiency gain that a real kernel implementation can provide (i.e. it will be slower than running on a more recent kernel).

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • As centos 7 is still supported I guess the openjdk might detect that and fallback to slow method? Is it open jdk or adoptium code? – Nicolas Henneaux Oct 29 '22 at 10:19
  • 1
    I checked only the OpenJDK code and that one doesn't seem to have any fallback that I could see (but might be in a code path that I haven't checked). I have no idea if Adoptium added/modified anything there. Depending on what the deliverable is, they *could* probably just ship the same binary in a container with a recent-enough glibc and call that "good enough". – Joachim Sauer Oct 29 '22 at 17:04