You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by us...@apache.org on 2016/12/16 21:10:19 UTC

lucene-solr:LUCENE-6989-v2: LUCENE-6989: Refactor code and add documentation

Repository: lucene-solr
Updated Branches:
  refs/heads/LUCENE-6989-v2 b8fe1ff83 -> ffc957fdb


LUCENE-6989: Refactor code and add documentation


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/ffc957fd
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/ffc957fd
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/ffc957fd

Branch: refs/heads/LUCENE-6989-v2
Commit: ffc957fdb3c21d110ab23392ed91e74cfc1f169d
Parents: b8fe1ff
Author: Uwe Schindler <us...@apache.org>
Authored: Fri Dec 16 22:09:54 2016 +0100
Committer: Uwe Schindler <us...@apache.org>
Committed: Fri Dec 16 22:09:54 2016 +0100

----------------------------------------------------------------------
 .../org/apache/lucene/store/MMapDirectory.java  | 63 +++++++++++---------
 1 file changed, 36 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ffc957fd/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java b/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
index c7ceeb3..fa2ed8d 100644
--- a/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
+++ b/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
@@ -175,7 +175,7 @@ public class MMapDirectory extends FSDirectory {
    * is closed while another thread is still accessing it (SIGSEGV).
    * <p>To enable the hack, the following requirements need to be
    * fulfilled: The used JVM must be Oracle Java / OpenJDK 8
-   * <em>(preliminary support for Java 9 (nocommit: build 148 or later) was added with Lucene 6.4)</em>.
+   * <em>(preliminary support for Java 9 EA build 150+ was added with Lucene 6.4)</em>.
    * In addition, the following permissions need to be granted
    * to {@code lucene-core.jar} in your
    * <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html">policy file</a>:
@@ -338,41 +338,48 @@ public class MMapDirectory extends FSDirectory {
   @SuppressForbidden(reason = "Needs access to private APIs in DirectBuffer, sun.misc.Cleaner, and sun.misc.Unsafe to enable hack")
   private static Object unmapHackImpl() {
     final Lookup lookup = lookup();
-    Class<?> unmappableBufferClass;
-    MethodHandle unmapper;
     try {
       try {
-        // *** Unsafe unmapping (Java 9+) ***
+        // *** sun.misc.Unsafe unmapping (Java 9+) ***
         final Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
-        // we do not need to check for a specific class, we can call the Unsafe method with any buffer class:
-        unmappableBufferClass = ByteBuffer.class;
         // first check if Unsafe has the right method, otherwise we can give up
         // without doing any security critical stuff:
-        unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner",
-            methodType(void.class, unmappableBufferClass));
+        final MethodHandle unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner",
+            methodType(void.class, ByteBuffer.class));
         // fetch the unsafe instance and bind it to the virtual MH:
         final Field f = unsafeClass.getDeclaredField("theUnsafe");
         f.setAccessible(true);
         final Object theUnsafe = f.get(null);
-        unmapper = unmapper.bindTo(theUnsafe);
+        return newBufferCleaner(ByteBuffer.class, unmapper.bindTo(theUnsafe));
       } catch (SecurityException se) {
         // rethrow to report errors correctly (we need to catch it here, as we also catch RuntimeException below!):
         throw se;
       } catch (ReflectiveOperationException | RuntimeException e) {
-        // *** legacy Java 8 unmapping with sun.misc.Cleaner ***
-        unmappableBufferClass = Class.forName("java.nio.DirectByteBuffer");
+        // *** sun.misc.Cleaner unmapping (Java 8) ***
+        final Class<?> unmappableBufferClass = Class.forName("java.nio.DirectByteBuffer");
         
         final Method m = unmappableBufferClass.getMethod("cleaner");
         m.setAccessible(true);
         final MethodHandle directBufferCleanerMethod = lookup.unreflect(m);
         final Class<?> cleanerClass = directBufferCleanerMethod.type().returnType();
         
+        /* "Compile" a MH that basically is equivalent to the following code:
+         * void unmapper(ByteBuffer byteBuffer) {
+         *   sun.misc.Cleaner cleaner = ((java.nio.DirectByteBuffer) byteBuffer).cleaner();
+         *   if (Objects.nonNull(cleaner)) {
+         *     cleaner.clean();
+         *   } else {
+         *     noop(cleaner); // the noop is needed because MethodHandles#guardWithTest always needs ELSE
+         *   }
+         * }
+         */
         final MethodHandle cleanMethod = lookup.findVirtual(cleanerClass, "clean", methodType(void.class));
         final MethodHandle nonNullTest = lookup.findStatic(Objects.class, "nonNull", methodType(boolean.class, Object.class))
             .asType(methodType(boolean.class, cleanerClass));
         final MethodHandle noop = dropArguments(constant(Void.class, null).asType(methodType(void.class)), 0, cleanerClass);
-        unmapper = filterReturnValue(directBufferCleanerMethod, guardWithTest(nonNullTest, cleanMethod, noop))
+        final MethodHandle unmapper = filterReturnValue(directBufferCleanerMethod, guardWithTest(nonNullTest, cleanMethod, noop))
             .asType(methodType(void.class, ByteBuffer.class));
+        return newBufferCleaner(unmappableBufferClass, unmapper);
       }
     } catch (SecurityException se) {
       return "Unmapping is not supported, because not all required permissions are given to the Lucene JAR file: " + se +
@@ -381,25 +388,27 @@ public class MMapDirectory extends FSDirectory {
     } catch (ReflectiveOperationException | RuntimeException e) {
       return "Unmapping is not supported on this platform, because internal Java APIs are not compatible to this Lucene version: " + e; 
     }
-    
-    final Class<?> unmappableBufferClass0 = unmappableBufferClass;
-    final MethodHandle unmapper0 = unmapper;
-    return (BufferCleaner) (String resourceDescription, ByteBuffer buffer) -> {
+  }
+  
+  private static BufferCleaner newBufferCleaner(final Class<?> unmappableBufferClass, final MethodHandle unmapper) {
+    assert Objects.equals(methodType(void.class, ByteBuffer.class), unmapper.type());
+    return (String resourceDescription, ByteBuffer buffer) -> {
       if (!buffer.isDirect()) {
         throw new IllegalArgumentException("Unmapping only works with direct buffers");
       }
-      if (unmappableBufferClass0.isInstance(buffer)) {
-        final Throwable error = AccessController.doPrivileged((PrivilegedAction<Throwable>) () -> {
-          try {
-            unmapper0.invokeExact(buffer);
-            return null;
-          } catch (Throwable t) {
-            return t;
-          }
-        });
-        if (error != null) {
-          throw new IOException("Unable to unmap the mapped buffer: " + resourceDescription, error);
+      if (!unmappableBufferClass.isInstance(buffer)) {
+        throw new IllegalArgumentException("ByteBuffer is not an instance of " + unmappableBufferClass.getName());
+      }
+      final Throwable error = AccessController.doPrivileged((PrivilegedAction<Throwable>) () -> {
+        try {
+          unmapper.invokeExact(buffer);
+          return null;
+        } catch (Throwable t) {
+          return t;
         }
+      });
+      if (error != null) {
+        throw new IOException("Unable to unmap the mapped buffer: " + resourceDescription, error);
       }
     };
   }