diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 6eada8787be..0be936905fe 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -577,6 +577,10 @@ Bug fixes throw NoSuchDirectoryException when all files written so far have been written to one directory, but the other still has not yet been created on the filesystem. (Robert Muir) + +* LUCENE-3409: IndexWriter.deleteAll was failing to close pooled NRT + SegmentReaders, leading to unused files accumulating in the + Directory. (tal steier via Mike McCandless) New Features diff --git a/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java b/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java index da1dc47ac81..75c430534a9 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexFileDeleter.java @@ -374,6 +374,10 @@ final class IndexFileDeleter { } public void refresh() throws IOException { + // Set to null so that we regenerate the list of pending + // files; else we can accumulate same file more than + // once + deletable = null; refresh(null); } diff --git a/lucene/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/src/java/org/apache/lucene/index/IndexWriter.java index c99d0c4f25a..a19c7c44233 100644 --- a/lucene/src/java/org/apache/lucene/index/IndexWriter.java +++ b/lucene/src/java/org/apache/lucene/index/IndexWriter.java @@ -600,6 +600,23 @@ public class IndexWriter implements Closeable, TwoPhaseCommit { drop(info, IOContext.Context.MERGE); } + public synchronized void dropAll() throws IOException { + Iterator> iter = readerMap.entrySet().iterator(); + while (iter.hasNext()) { + + final Map.Entry ent = iter.next(); + + SegmentReader sr = ent.getValue(); + sr.hasChanges = false; + iter.remove(); + + // NOTE: it is allowed that this decRef does not + // actually close the SR; this can happen when a + // near real-time reader using this SR is still open + sr.decRef(); + } + } + public synchronized void drop(SegmentInfo info, IOContext.Context context) throws IOException { final SegmentReader sr; if ((sr = readerMap.remove(new SegmentCacheKey(info, context))) != null) { @@ -2141,7 +2158,7 @@ public class IndexWriter implements Closeable, TwoPhaseCommit { deleter.refresh(); // Don't bother saving any changes in our segmentInfos - readerPool.clear(null); + readerPool.dropAll(); // Mark that the index has changed ++changeCount; @@ -3698,7 +3715,6 @@ public class IndexWriter implements Closeable, TwoPhaseCommit { synchronized(this) { deleter.deleteFile(compoundFileName); - deleter.deleteFile(IndexFileNames.segmentFileName(mergedName, "", IndexFileNames.COMPOUND_FILE_ENTRIES_EXTENSION)); deleter.deleteNewFiles(merge.info.files()); } diff --git a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java index 8006985e456..5a9cec7d8cc 100644 --- a/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -1849,4 +1849,28 @@ public class TestIndexWriter extends LuceneTestCase { writer.close(); dir.close(); } + + public void testDeleteAllNRTLeftoverFiles() throws Exception { + + Directory d = new MockDirectoryWrapper(random, new RAMDirectory()); + IndexWriter w = new IndexWriter(d, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random))); + Document doc = new Document(); + for(int i = 0; i < 20; i++) { + for(int j = 0; j < 100; ++j) { + w.addDocument(doc); + } + w.commit(); + IndexReader.open(w, true).close(); + + w.deleteAll(); + w.commit(); + + // Make sure we accumulate no files except for empty + // segments_N and segments.gen: + assertTrue(d.listAll().length <= 2); + } + + w.close(); + d.close(); + } }