mirror of https://github.com/apache/lucene.git
LUCENE-6614: Improve partition detection in IOUtils#spins() so it works with NVMe drives
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1687883 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
878881a77a
commit
ff5e36abcc
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 LuceneTestCase {
|
|||
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();
|
||||
|
@ -401,4 +431,39 @@ public class TestIOUtils extends LuceneTestCase {
|
|||
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);
|
||||
|
||||
Path mockPath = mockLinux.getPath(dir.toString());
|
||||
assertFalse(IOUtils.spinsLinux(mockPath));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in New Issue