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 2021/12/21 12:06:49 UTC

[lucene] 01/02: LUCENE-10330: Make the mmap directory tests fail by default, if unmapping does not work (#556)

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

uschindler pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 1cc1e54245a7174fb5bcc439578ec2289f5f2206
Author: Uwe Schindler <us...@apache.org>
AuthorDate: Tue Dec 21 13:00:10 2021 +0100

    LUCENE-10330: Make the mmap directory tests fail by default, if unmapping does not work (#556)
    
    Co-authored-by: Dawid Weiss <da...@gmail.com>
---
 lucene/core.tests/build.gradle                     | 28 +++++++++++++++++
 lucene/core.tests/src/test/module-info.java        | 25 ++++++++++++++++
 .../org/apache/lucene/core/tests/TestMMap.java     | 35 ++++++++++++++++++++++
 .../org/apache/lucene/store/MMapDirectory.java     | 20 ++++++-------
 .../org/apache/lucene/store/TestMmapDirectory.java |  8 ++---
 .../org/apache/lucene/store/TestMultiMMap.java     |  8 ++---
 settings.gradle                                    |  1 +
 7 files changed, 107 insertions(+), 18 deletions(-)

diff --git a/lucene/core.tests/build.gradle b/lucene/core.tests/build.gradle
new file mode 100644
index 0000000..9ada300
--- /dev/null
+++ b/lucene/core.tests/build.gradle
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+apply plugin: 'java-library'
+
+description = 'Module tests for :lucene:core'
+
+dependencies {
+  moduleTestImplementation project(':lucene:core')
+  moduleTestImplementation("junit:junit", {
+    exclude group: "org.hamcrest"
+  })
+  moduleTestImplementation "org.hamcrest:hamcrest"
+}
diff --git a/lucene/core.tests/src/test/module-info.java b/lucene/core.tests/src/test/module-info.java
new file mode 100644
index 0000000..9b3cf5a
--- /dev/null
+++ b/lucene/core.tests/src/test/module-info.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Test module for {@code org.apache.lucene.core}. */
+@SuppressWarnings({"requires-automatic"})
+module org.apache.lucene.core.tests {
+  requires org.apache.lucene.core;
+  requires junit;
+
+  exports org.apache.lucene.core.tests;
+}
diff --git a/lucene/core.tests/src/test/org/apache/lucene/core/tests/TestMMap.java b/lucene/core.tests/src/test/org/apache/lucene/core/tests/TestMMap.java
new file mode 100644
index 0000000..2324846
--- /dev/null
+++ b/lucene/core.tests/src/test/org/apache/lucene/core/tests/TestMMap.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.core.tests;
+
+import org.apache.lucene.store.MMapDirectory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestMMap {
+  @Test
+  public void testUnmapSupported() throws Exception {
+    final Module module = MMapDirectory.class.getModule();
+    Assert.assertTrue("Lucene Core is not loaded as module", module.isNamed());
+    Assert.assertTrue(
+        "Lucene Core can't read 'jdk.unsupported' module",
+        module.getLayer().findModule("jdk.unsupported").map(module::canRead).orElse(false));
+
+    // check that MMapDirectory can unmap by running the autodetection logic:
+    Assert.assertTrue(MMapDirectory.UNMAP_NOT_SUPPORTED_REASON, MMapDirectory.UNMAP_SUPPORTED);
+  }
+}
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 161cc38..6e5b181 100644
--- a/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
+++ b/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java
@@ -346,9 +346,7 @@ public class MMapDirectory extends FSDirectory {
     }
   }
 
-  @SuppressForbidden(
-      reason =
-          "Needs access to private APIs in DirectBuffer, sun.misc.Cleaner, and sun.misc.Unsafe to enable hack")
+  @SuppressForbidden(reason = "Needs access to sun.misc.Unsafe to enable hack")
   private static Object unmapHackImpl() {
     final Lookup lookup = lookup();
     try {
@@ -363,29 +361,31 @@ public class MMapDirectory extends FSDirectory {
       final Field f = unsafeClass.getDeclaredField("theUnsafe");
       f.setAccessible(true);
       final Object theUnsafe = f.get(null);
-      return newBufferCleaner(ByteBuffer.class, unmapper.bindTo(theUnsafe));
+      return newBufferCleaner(unmapper.bindTo(theUnsafe));
     } catch (SecurityException se) {
       return "Unmapping is not supported, because not all required permissions are given to the Lucene JAR file: "
           + se
           + " [Please grant at least the following permissions: RuntimePermission(\"accessClassInPackage.sun.misc\") "
           + " and ReflectPermission(\"suppressAccessChecks\")]";
     } catch (ReflectiveOperationException | RuntimeException e) {
+      final Module module = MMapDirectory.class.getModule();
+      final ModuleLayer layer = module.getLayer();
+      // classpath / unnamed module has no layer, so we need to check:
+      if (layer != null
+          && layer.findModule("jdk.unsupported").map(module::canRead).orElse(false) == false) {
+        return "Unmapping is not supported, because Lucene cannot read 'jdk.unsupported' module.";
+      }
       return "Unmapping is not supported on this platform, because internal Java APIs are not compatible with this Lucene version: "
           + e;
     }
   }
 
-  private static BufferCleaner newBufferCleaner(
-      final Class<?> unmappableBufferClass, final MethodHandle unmapper) {
+  private static BufferCleaner newBufferCleaner(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 (!unmappableBufferClass.isInstance(buffer)) {
-        throw new IllegalArgumentException(
-            "buffer is not an instance of " + unmappableBufferClass.getName());
-      }
       final Throwable error =
           AccessController.doPrivileged(
               (PrivilegedAction<Throwable>)
diff --git a/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java b/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java
index 1ae552b..46c5934 100644
--- a/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java
+++ b/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 
 /** Tests MMapDirectory */
@@ -34,10 +35,9 @@ public class TestMmapDirectory extends BaseDirectoryTestCase {
     return m;
   }
 
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-    assumeTrue(MMapDirectory.UNMAP_NOT_SUPPORTED_REASON, MMapDirectory.UNMAP_SUPPORTED);
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    assertTrue(MMapDirectory.UNMAP_NOT_SUPPORTED_REASON, MMapDirectory.UNMAP_SUPPORTED);
   }
 
   @Ignore(
diff --git a/lucene/core/src/test/org/apache/lucene/store/TestMultiMMap.java b/lucene/core/src/test/org/apache/lucene/store/TestMultiMMap.java
index b5d22e8..317e4a8 100644
--- a/lucene/core/src/test/org/apache/lucene/store/TestMultiMMap.java
+++ b/lucene/core/src/test/org/apache/lucene/store/TestMultiMMap.java
@@ -19,6 +19,7 @@ package org.apache.lucene.store;
 import java.io.IOException;
 import java.nio.file.Path;
 import org.apache.lucene.util.BytesRef;
+import org.junit.BeforeClass;
 
 /**
  * Tests MMapDirectory's MultiMMapIndexInput
@@ -33,10 +34,9 @@ public class TestMultiMMap extends BaseChunkedDirectoryTestCase {
     return new MMapDirectory(path, maxChunkSize);
   }
 
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-    assumeTrue(MMapDirectory.UNMAP_NOT_SUPPORTED_REASON, MMapDirectory.UNMAP_SUPPORTED);
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    assertTrue(MMapDirectory.UNMAP_NOT_SUPPORTED_REASON, MMapDirectory.UNMAP_SUPPORTED);
   }
 
   // TODO: can we improve ByteBuffersDirectory (without overhead) and move these clone safety tests
diff --git a/settings.gradle b/settings.gradle
index 2d48e41..ed641bf 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -41,6 +41,7 @@ include "lucene:benchmark"
 include "lucene:classification"
 include "lucene:codecs"
 include "lucene:core"
+include "lucene:core.tests"
 include "lucene:demo"
 include "lucene:distribution"
 include "lucene:distribution.tests"