This is an automated email from the ASF dual-hosted git repository.

ivandasch pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new eeb5535fe33 IGNITE-20515 Fix MappedFile.map for JDK 14 and newer. 
(#10961)
eeb5535fe33 is described below

commit eeb5535fe3323f85b4790b835010287a37f58551
Author: Ivan Daschinskiy <[email protected]>
AuthorDate: Mon Oct 2 14:31:04 2023 +0300

    IGNITE-20515 Fix MappedFile.map for JDK 14 and newer. (#10961)
---
 .../ignite/internal/mem/file/MappedFile.java       | 186 ++++++++++++++++++---
 1 file changed, 163 insertions(+), 23 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java
index 4b7552491c6..f264d87a315 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java
@@ -19,26 +19,28 @@ package org.apache.ignite.internal.mem.file;
 
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.mem.DirectMemoryRegion;
 import org.apache.ignite.internal.mem.UnsafeChunk;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import sun.nio.ch.FileChannelImpl;
 
+import static org.apache.ignite.internal.util.IgniteUtils.jdkVersion;
+import static org.apache.ignite.internal.util.IgniteUtils.majorJavaVersion;
+
 /** */
 public class MappedFile implements Closeable, DirectMemoryRegion {
-    /** */
-    private static final Method map0 = 
U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class, 
long.class);
-
-    /** */
-    private static final Method unmap0 = 
U.findNonPublicMethod(FileChannelImpl.class, "unmap0", long.class, long.class);
-
     /** */
     public static final int MAP_RW = 1;
 
+    /** File memory mapper */
+    private static final Mapper mapper = pickMapper();
+
     /** */
     private final RandomAccessFile file;
 
@@ -85,7 +87,7 @@ public class MappedFile implements Closeable, 
DirectMemoryRegion {
     /** {@inheritDoc} */
     @Override public void close() throws IOException {
         try {
-            unmap(addr, size);
+            mapper.unmap(addr, size);
         }
         finally {
             file.close();
@@ -122,16 +124,7 @@ public class MappedFile implements Closeable, 
DirectMemoryRegion {
      * @throws IOException
      */
     public static long map(RandomAccessFile f, int mode, long start, long 
size) throws IOException {
-        try {
-            return (Long)map0.invoke(f.getChannel(), mode, start, size);
-        }
-        catch (IllegalAccessException e) {
-            throw new IllegalStateException(e);
-        }
-        catch (InvocationTargetException e) {
-            Throwable target = e.getTargetException();
-            throw (target instanceof IOException) ? (IOException)target : new 
IOException(target);
-        }
+        return mapper.map(f, mode, start, size);
     }
 
     /**
@@ -141,14 +134,161 @@ public class MappedFile implements Closeable, 
DirectMemoryRegion {
      * @param size Size of the mapped file.
      */
     public static void unmap(long addr, long size) {
-        try {
-            unmap0.invoke(null, addr, size);
+        mapper.unmap(addr, size);
+    }
+
+    /** */
+    private static Mapper pickMapper() {
+        int javaVersion = majorJavaVersion(jdkVersion());
+
+        if (javaVersion >= 19)
+            return new JDK19Mapper();
+
+        if (javaVersion >= 14)
+            return new JDK14Mapper();
+
+        return new LegacyMapper();
+    }
+
+    /** */
+    private interface Mapper {
+        /** */
+        long map(RandomAccessFile f, int mode, long start, long size) throws 
IOException;
+
+        /** */
+        void unmap(long addr, long size);
+    }
+
+    /** */
+    private static class LegacyMapper implements Mapper {
+        /** */
+        private static final Method map0 = 
U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class, 
long.class);
+
+        /** */
+        private static final Method unmap0 = 
U.findNonPublicMethod(FileChannelImpl.class, "unmap0", long.class, long.class);
+
+
+        /** {@inheritDoc} */
+        @Override public long map(RandomAccessFile f, int mode, long start, 
long size) throws IOException {
+            try {
+                return (Long)map0.invoke(f.getChannel(), mode, start, size);
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+            catch (InvocationTargetException e) {
+                Throwable target = e.getTargetException();
+                throw (target instanceof IOException) ? (IOException)target : 
new IOException(target);
+            }
         }
-        catch (IllegalAccessException e) {
-            throw new IllegalStateException(e);
+
+        /** {@inheritDoc} */
+        @Override public void unmap(long addr, long size) {
+            try {
+                unmap0.invoke(null, addr, size);
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+            catch (InvocationTargetException e) {
+                throw new IllegalStateException(e.getTargetException());
+            }
         }
-        catch (InvocationTargetException e) {
-            throw new IllegalStateException(e.getTargetException());
+    }
+
+    /** */
+    private static class JDK14Mapper extends LegacyMapper {
+        /** Method {@link FileChannelImpl#map0} has additional parameter since 
JDK 14, isSync, {@code false} by default. */
+        private static final Method map0 = 
U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class,
+                long.class, boolean.class);
+
+        /** {@inheritDoc} */
+        @Override public long map(RandomAccessFile f, int mode, long start, 
long size) throws IOException {
+            try {
+                return (Long)map0.invoke(f.getChannel(), mode, start, size, 
false);
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+            catch (InvocationTargetException e) {
+                Throwable target = e.getTargetException();
+                throw (target instanceof IOException) ? (IOException)target : 
new IOException(target);
+            }
+        }
+    }
+
+    /** */
+    private static class JDK19Mapper implements Mapper {
+        /**  */
+        private static final Method map;
+
+        /** */
+        private static final Method unmap;
+
+        /** */
+        private static final Object dispatcher;
+
+        static {
+            try {
+                // These methods are still in {@link FileChannelImpl} class in 
JDK 19.
+                Method map0 = U.findNonPublicMethod(FileChannelImpl.class, 
"map0", FileDescriptor.class, int.class,
+                        long.class, long.class, boolean.class);
+
+                Method unmap0 = U.findNonPublicMethod(FileChannelImpl.class, 
"unmap0", long.class, long.class);
+
+                if (map0 != null && unmap0 != null) {
+                    map = map0;
+                    unmap = unmap0;
+                    dispatcher = null;
+                }
+                else {
+                    // That methods are moved to {@link 
sun.nio.ch.FileDispatcher}.
+                    Class<?> fileDispatcherCls = 
Class.forName("sun.nio.ch.FileDispatcher");
+
+                    dispatcher = U.staticField(FileChannelImpl.class, "nd");
+
+                    map = U.findNonPublicMethod(fileDispatcherCls, "map", 
FileDescriptor.class, int.class,
+                            long.class, long.class, boolean.class);
+
+                    unmap = U.findNonPublicMethod(fileDispatcherCls, "unmap", 
long.class, long.class);
+
+                }
+            }
+            catch (ClassNotFoundException | IgniteCheckedException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public long map(RandomAccessFile f, int mode, long start, 
long size) throws IOException {
+            try {
+                Object fd = U.field(f.getChannel(), "fd");
+
+                if (dispatcher != null)
+                    return (Long)map.invoke(dispatcher, fd, mode, start, size, 
false);
+                else
+                    return (Long)map.invoke(f.getChannel(), fd, mode, start, 
size, false);
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+            catch (InvocationTargetException e) {
+                Throwable target = e.getTargetException();
+                throw (target instanceof IOException) ? (IOException)target : 
new IOException(target);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void unmap(long addr, long size) {
+            try {
+                unmap.invoke(dispatcher, addr, size); // If dispatcher is 
null, the static method will be called.
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            }
+            catch (InvocationTargetException e) {
+                throw new IllegalStateException(e.getTargetException());
+            }
         }
     }
 }

Reply via email to