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 2015/06/27 05:35:01 UTC

svn commit: r1687883 - in /lucene/dev/trunk/lucene: CHANGES.txt core/src/java/org/apache/lucene/util/IOUtils.java core/src/test/org/apache/lucene/util/TestIOUtils.java tools/junit4/tests.policy

Author: uschindler
Date: Sat Jun 27 03:35:00 2015
New Revision: 1687883

URL: http://svn.apache.org/r1687883
Log:
LUCENE-6614: Improve partition detection in IOUtils#spins() so it works with NVMe drives

Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/util/IOUtils.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestIOUtils.java
    lucene/dev/trunk/lucene/tools/junit4/tests.policy

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1687883&r1=1687882&r2=1687883&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Sat Jun 27 03:35:00 2015
@@ -179,6 +179,9 @@ Bug fixes
 * LUCENE-6608: Fix potential resource leak in BigramDictionary.
   (Rishabh Patel via Uwe Schindler)
 
+* LUCENE-6614: Improve partition detection in IOUtils#spins() so it
+  works with NVMe drives.  (Uwe Schindler, Mike McCandless)
+
 Changes in Runtime Behavior
 
 * LUCENE-6501: The subreader structure in ParallelCompositeReader

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/util/IOUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/util/IOUtils.java?rev=1687883&r1=1687882&r2=1687883&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/util/IOUtils.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/util/IOUtils.java Sat Jun 27 03:35:00 2015
@@ -28,6 +28,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.DirectoryStream;
 import java.nio.file.FileStore;
 import java.nio.file.FileVisitResult;
 import java.nio.file.FileVisitor;
@@ -493,23 +494,28 @@ public final class IOUtils {
     // /devices/XXX -> sda0
     devName = path.getRoot().resolve(devName).toRealPath().getFileName().toString();
   
-    // now read:
-    Path sysinfo = path.getRoot().resolve("sys/block");
-    Path devinfo = sysinfo.resolve(devName);
-    
-    // tear away partition numbers until we find it.
-    while (!Files.exists(devinfo)) {
-      if (!devName.isEmpty() && Character.isDigit(devName.charAt(devName.length()-1))) {
-        devName = devName.substring(0, devName.length()-1);
-      } else {
-        break; // give up
+    // now try to find the longest matching device folder in /sys/block
+    // (that starts with our dev name):
+    Path sysinfo = path.getRoot().resolve("sys").resolve("block");
+    Path devsysinfo = null;
+    int matchlen = 0;
+    try (DirectoryStream<Path> stream = Files.newDirectoryStream(sysinfo)) {
+      for (Path device : stream) {
+        String name = device.getFileName().toString();
+        if (name.length() > matchlen && devName.startsWith(name)) {
+          devsysinfo = device;
+          matchlen = name.length();
+        }
       }
-      devinfo = sysinfo.resolve(devName);
+    }
+    
+    if (devsysinfo == null) {
+      return true; // give up
     }
     
     // read first byte from rotational, it's a 1 if it spins.
-    Path info = devinfo.resolve("queue/rotational");
-    try (InputStream stream = Files.newInputStream(info)) {
+    Path rotational = devsysinfo.resolve("queue").resolve("rotational");
+    try (InputStream stream = Files.newInputStream(rotational)) {
       return stream.read() == '1'; 
     }
   }

Modified: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestIOUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestIOUtils.java?rev=1687883&r1=1687882&r2=1687883&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestIOUtils.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/util/TestIOUtils.java Sat Jun 27 03:35:00 2015
@@ -32,6 +32,8 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
 
 import org.apache.lucene.mockfile.FilterFileSystem;
 import org.apache.lucene.mockfile.FilterFileSystemProvider;
@@ -353,6 +355,34 @@ public class TestIOUtils extends LuceneT
     assertFalse(IOUtils.spinsLinux(mockPath));
   }
   
+  public void testNVME() throws Exception {
+    assumeFalse("windows is not supported", Constants.WINDOWS);
+    Path dir = createTempDir();
+    dir = FilterPath.unwrap(dir).toRealPath();
+    
+    // fake ssd
+    FileStore root = new MockFileStore(dir.toString() + " (/dev/nvme0n1p1)", "btrfs", "/dev/nvme0n1p1");
+    // make a fake /dev/nvme0n1p1 for it
+    Path devdir = dir.resolve("dev");
+    Files.createDirectories(devdir);
+    Files.createFile(devdir.resolve("nvme0n1p1"));
+    // make a fake /sys/block/nvme0n1/queue/rotational file for it
+    Path sysdir = dir.resolve("sys").resolve("block").resolve("nvme0n1").resolve("queue");
+    Files.createDirectories(sysdir);
+    try (OutputStream o = Files.newOutputStream(sysdir.resolve("rotational"))) {
+      o.write("0\n".getBytes(StandardCharsets.US_ASCII));
+    }
+    // As test for the longest path match, add some other devices (that have no queue/rotational), too:
+    Files.createFile(dir.resolve("sys").resolve("block").resolve("nvme0"));
+    Files.createFile(dir.resolve("sys").resolve("block").resolve("dummy"));
+    Files.createFile(dir.resolve("sys").resolve("block").resolve("nvm"));
+    Map<String,FileStore> mappings = Collections.singletonMap(dir.toString(), root);
+    FileSystem mockLinux = new MockLinuxFileSystemProvider(dir.getFileSystem(), mappings, dir).getFileSystem(null);
+    
+    Path mockPath = mockLinux.getPath(dir.toString());
+    assertFalse(IOUtils.spinsLinux(mockPath));
+  }
+  
   public void testRotatingPlatters() throws Exception {
     assumeFalse("windows is not supported", Constants.WINDOWS);
     Path dir = createTempDir();
@@ -393,6 +423,41 @@ public class TestIOUtils extends LuceneT
     Files.createDirectories(sysdir);
     try (OutputStream o = Files.newOutputStream(sysdir.resolve("rotational"))) {
       o.write("0\n".getBytes(StandardCharsets.US_ASCII));
+    }
+    Map<String,FileStore> mappings = Collections.singletonMap(dir.toString(), root);
+    FileSystem mockLinux = new MockLinuxFileSystemProvider(dir.getFileSystem(), mappings, dir).getFileSystem(null);
+    
+    Path mockPath = mockLinux.getPath(dir.toString());
+    assertFalse(IOUtils.spinsLinux(mockPath));
+  }
+  
+  public void testSymlinkSSD() throws Exception {
+    assumeFalse("windows is not supported", Constants.WINDOWS);
+    Path dir = createTempDir();
+    dir = FilterPath.unwrap(dir).toRealPath();
+    
+    // fake SSD with a symlink mount (Ubuntu-like):
+    Random rnd = random();
+    String partitionUUID = new UUID(rnd.nextLong(), rnd.nextLong()).toString();
+    FileStore root = new MockFileStore(dir.toString() + " (/dev/disk/by-uuid/"+partitionUUID+")", "btrfs", "/dev/disk/by-uuid/"+partitionUUID);
+    // make a fake /dev/sda1 for it
+    Path devdir = dir.resolve("dev");
+    Files.createDirectories(devdir);
+    Path deviceFile = devdir.resolve("sda1");
+    Files.createFile(deviceFile);
+    // create a symlink to the above device file
+    Path symlinkdir = devdir.resolve("disk").resolve("by-uuid");
+    Files.createDirectories(symlinkdir);
+    try {
+      Files.createSymbolicLink(symlinkdir.resolve(partitionUUID), deviceFile);
+    } catch (UnsupportedOperationException | IOException e) {
+      assumeNoException("test requires filesystem that supports symbolic links", e);
+    }
+    // make a fake /sys/block/sda/queue/rotational file for it
+    Path sysdir = dir.resolve("sys").resolve("block").resolve("sda").resolve("queue");
+    Files.createDirectories(sysdir);
+    try (OutputStream o = Files.newOutputStream(sysdir.resolve("rotational"))) {
+      o.write("0\n".getBytes(StandardCharsets.US_ASCII));
     }
     Map<String,FileStore> mappings = Collections.singletonMap(dir.toString(), root);
     FileSystem mockLinux = new MockLinuxFileSystemProvider(dir.getFileSystem(), mappings, dir).getFileSystem(null);

Modified: lucene/dev/trunk/lucene/tools/junit4/tests.policy
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/tools/junit4/tests.policy?rev=1687883&r1=1687882&r2=1687883&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/tools/junit4/tests.policy (original)
+++ lucene/dev/trunk/lucene/tools/junit4/tests.policy Sat Jun 27 03:35:00 2015
@@ -38,6 +38,9 @@ grant {
   permission java.io.FilePermission "${junit4.childvm.cwd}${/}jacoco.db", "write";
   permission java.io.FilePermission "${junit4.tempDir}${/}*", "read,write,delete";
   permission java.io.FilePermission "${clover.db.dir}${/}-", "read,write,delete";
+  
+  // needed by SSD detection tests in TestIOUtils (creates symlinks)
+  permission java.nio.file.LinkPermission "symbolic";
 
   // needed by gson serialization of junit4 runner: TODO clean that up
   permission java.lang.RuntimePermission "accessDeclaredMembers";