From f8bd22e58c953a5ef27fd4859c91845755ebd490 Mon Sep 17 00:00:00 2001 From: Mike McCandless Date: Sun, 7 Feb 2016 13:21:39 -0500 Subject: [PATCH] LUCENE-6835, LUCENE-6684: move the 'suppress NSFE on windows' hack down lower, out of IFD into FSDir; also fix IFD to remove segments files before others --- .../apache/lucene/index/IndexFileDeleter.java | 27 ++++--- .../org/apache/lucene/store/FSDirectory.java | 15 +++- .../lucene/index/TestIndexFileDeleter.java | 76 +++++++++++++++++++ 3 files changed, 100 insertions(+), 18 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/index/IndexFileDeleter.java b/lucene/core/src/java/org/apache/lucene/index/IndexFileDeleter.java index 6886055fb6c..52f0b401aff 100644 --- a/lucene/core/src/java/org/apache/lucene/index/IndexFileDeleter.java +++ b/lucene/core/src/java/org/apache/lucene/index/IndexFileDeleter.java @@ -696,24 +696,23 @@ final class IndexFileDeleter implements Closeable { ensureOpen(); if (infoStream.isEnabled("IFD")) { - infoStream.message("IFD", "delete \"" + names + "\""); + infoStream.message("IFD", "delete " + names + ""); + } + + // We make two passes, first deleting any segments_N files, second deleting the rest. We do this so that if we throw exc or JVM + // crashes during deletions, even when not on Windows, we don't leave the index in an "apparently corrupt" state: + for(String name : names) { + if (name.startsWith(IndexFileNames.SEGMENTS) == false) { + continue; + } + directory.deleteFile(name); } for(String name : names) { - try { - directory.deleteFile(name); - } catch (NoSuchFileException | FileNotFoundException e) { - // IndexWriter should only ask us to delete files it knows it wrote, so if we hit this, something is wrong! - - if (Constants.WINDOWS) { - // TODO: can we remove this OS-specific hacky logic? If windows deleteFile is buggy, we should instead contain this workaround in - // a WindowsFSDirectory ... - // LUCENE-6684: we suppress this assert for Windows, since a file could be in a confusing "pending delete" state, and falsely - // return NSFE/FNFE - } else { - throw e; - } + if (name.startsWith(IndexFileNames.SEGMENTS) == true) { + continue; } + directory.deleteFile(name); } } diff --git a/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java b/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java index 32e078caa52..26e45531aa2 100644 --- a/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java +++ b/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java @@ -327,7 +327,7 @@ public abstract class FSDirectory extends BaseDirectory { if (pendingDeletes.contains(name)) { throw new NoSuchFileException("file \"" + name + "\" is already pending delete"); } - privateDeleteFile(name); + privateDeleteFile(name, false); maybeDeletePendingFiles(); } @@ -347,7 +347,7 @@ public abstract class FSDirectory extends BaseDirectory { // Clone the set since we mutate it in privateDeleteFile: for(String name : new HashSet<>(pendingDeletes)) { - privateDeleteFile(name); + privateDeleteFile(name, true); } } } @@ -363,14 +363,21 @@ public abstract class FSDirectory extends BaseDirectory { } } - private void privateDeleteFile(String name) throws IOException { + private void privateDeleteFile(String name, boolean isPendingDelete) throws IOException { try { Files.delete(directory.resolve(name)); pendingDeletes.remove(name); } catch (NoSuchFileException | FileNotFoundException e) { // We were asked to delete a non-existent file: pendingDeletes.remove(name); - throw e; + if (isPendingDelete && Constants.WINDOWS) { + // TODO: can we remove this OS-specific hacky logic? If windows deleteFile is buggy, we should instead contain this workaround in + // a WindowsFSDirectory ... + // LUCENE-6684: we suppress this check for Windows, since a file could be in a confusing "pending delete" state, failing the first + // delete attempt with access denied and then apparently falsely failing here when we try ot delete it again, with NSFE/FNFE + } else { + throw e; + } } catch (IOException ioe) { // On windows, a file delete can fail because there's still an open // file handle against it. We record this in pendingDeletes and diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java index 3ea9da004b5..ecebb18c16e 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexFileDeleter.java @@ -488,4 +488,80 @@ public class TestIndexFileDeleter extends LuceneTestCase { w.close(); dir.close(); } + + // LUCENE-6835: make sure best-effort to not create an "apparently but not really" corrupt index is working: + public void testExcInDeleteFile() throws Throwable { + int iters = atLeast(10); + for(int iter=0;iter