You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2017/09/09 06:17:15 UTC

lucene-solr:branch_7x: LUCENE-7959: Improve NativeFSLockFactory's NoSuchFileException

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_7x a1c584d54 -> bcdac5fef


LUCENE-7959: Improve NativeFSLockFactory's NoSuchFileException


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

Branch: refs/heads/branch_7x
Commit: bcdac5fef3ac0a8de074ca8308206e39d81e439f
Parents: a1c584d
Author: Robert Muir <rm...@apache.org>
Authored: Sat Sep 9 02:00:47 2017 -0400
Committer: Robert Muir <rm...@apache.org>
Committed: Sat Sep 9 02:05:33 2017 -0400

----------------------------------------------------------------------
 lucene/CHANGES.txt                              |  4 ++
 .../lucene/store/NativeFSLockFactory.java       | 14 ++++++-
 .../lucene/store/TestNativeFSLockFactory.java   | 42 ++++++++++++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bcdac5fe/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 41c559c..4a8e247 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -47,6 +47,10 @@ Bug Fixes
 * LUCENE-7891: Lucene's taxonomy facets now uses a non-buggy LRU cache
   by default.  (Jan-Willem van den Broek via Mike McCandless)
 
+* LUCENE-7959: Improve NativeFSLockFactory's exception message if it cannot create
+  write.lock for an empty index due to bad permissions/read-only filesystem/etc.
+  (Erick Erickson, Shawn Heisey, Robert Muir)
+
 Build
 
 * SOLR-11181: Switch order of maven artifact publishing procedure: deploy first

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bcdac5fe/lucene/core/src/java/org/apache/lucene/store/NativeFSLockFactory.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/java/org/apache/lucene/store/NativeFSLockFactory.java b/lucene/core/src/java/org/apache/lucene/store/NativeFSLockFactory.java
index 4f17d95..106b02e 100644
--- a/lucene/core/src/java/org/apache/lucene/store/NativeFSLockFactory.java
+++ b/lucene/core/src/java/org/apache/lucene/store/NativeFSLockFactory.java
@@ -93,15 +93,27 @@ public final class NativeFSLockFactory extends FSLockFactory {
     
     Path lockFile = lockDir.resolve(lockName);
 
+    IOException creationException = null;
     try {
       Files.createFile(lockFile);
     } catch (IOException ignore) {
       // we must create the file to have a truly canonical path.
       // if it's already created, we don't care. if it cant be created, it will fail below.
+      creationException = ignore;
     }
     
     // fails if the lock file does not exist
-    final Path realPath = lockFile.toRealPath();
+    final Path realPath;
+    try {
+      realPath = lockFile.toRealPath();
+    } catch (IOException e) {
+      // if we couldn't resolve the lock file, it might be because we couldn't create it.
+      // so append any exception from createFile as a suppressed exception, in case its useful
+      if (creationException != null) {
+        e.addSuppressed(creationException);
+      }
+      throw e;
+    }
     
     // used as a best-effort check, to see if the underlying file has changed
     final FileTime creationTime = Files.readAttributes(realPath, BasicFileAttributes.class).creationTime();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bcdac5fe/lucene/core/src/test/org/apache/lucene/store/TestNativeFSLockFactory.java
----------------------------------------------------------------------
diff --git a/lucene/core/src/test/org/apache/lucene/store/TestNativeFSLockFactory.java b/lucene/core/src/test/org/apache/lucene/store/TestNativeFSLockFactory.java
index 5d202bf..dc77178 100644
--- a/lucene/core/src/test/org/apache/lucene/store/TestNativeFSLockFactory.java
+++ b/lucene/core/src/test/org/apache/lucene/store/TestNativeFSLockFactory.java
@@ -18,9 +18,17 @@ package org.apache.lucene.store;
 
 
 import java.io.IOException;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.FileSystem;
 import java.nio.file.Files;
+import java.nio.file.OpenOption;
 import java.nio.file.Path;
+import java.nio.file.attribute.FileAttribute;
+import java.util.Set;
 
+import org.apache.lucene.mockfile.FilterFileSystemProvider;
+import org.apache.lucene.mockfile.FilterPath;
 import org.apache.lucene.util.IOUtils;
 import org.apache.lucene.util.TestUtil;
 
@@ -89,4 +97,38 @@ public class TestNativeFSLockFactory extends BaseLockFactoryTestCase {
       IOUtils.closeWhileHandlingException(lock);
     }
   }
+
+  /** MockFileSystem that throws AccessDeniedException on creating test.lock */
+  static class MockBadPermissionsFileSystem extends FilterFileSystemProvider {
+    public MockBadPermissionsFileSystem(FileSystem delegateInstance) {
+      super("mockbadpermissions://", delegateInstance);
+    }
+
+    @Override
+    public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+      if (path.getFileName().toString().equals("test.lock")) {
+        throw new AccessDeniedException(path.toString(), null, "fake access denied");
+      }
+      return super.newByteChannel(path, options, attrs);
+    }
+  }
+
+  public void testBadPermissions() throws IOException {
+    // create a mock filesystem that will throw exc on creating test.lock
+    Path tmpDir = createTempDir();
+    tmpDir = FilterPath.unwrap(tmpDir).toRealPath();
+    FileSystem mock = new MockBadPermissionsFileSystem(tmpDir.getFileSystem()).getFileSystem(null);
+    Path mockPath = mock.getPath(tmpDir.toString());
+
+    // we should get an IOException (typically NoSuchFileException but no guarantee) with
+    // our fake AccessDenied added as suppressed.
+    Directory dir = getDirectory(mockPath.resolve("indexDir"));
+    IOException expected = expectThrows(IOException.class, () -> {
+      dir.obtainLock("test.lock");
+    });
+    AccessDeniedException suppressed = (AccessDeniedException) expected.getSuppressed()[0];
+    assertTrue(suppressed.getMessage().contains("fake access denied"));
+
+    dir.close();
+  }
 }