Index: src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- src/java/org/apache/lucene/index/DirectoryReader.java (revision 782754) +++ src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -36,7 +36,6 @@ import org.apache.lucene.store.Lock; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.AlreadyClosedException; -import org.apache.lucene.store.FSDirectory; /** * An IndexReader which reads indexes with multiple segments. @@ -44,7 +43,6 @@ class DirectoryReader extends IndexReader implements Cloneable { protected Directory directory; protected boolean readOnly; - protected boolean closeDirectory; IndexWriter writer; @@ -64,7 +62,7 @@ private int numDocs = -1; private boolean hasDeletions = false; - static IndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { + static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { SegmentInfos.FindSegmentsFile finder = new SegmentInfos.FindSegmentsFile(directory) { protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException { @@ -73,39 +71,19 @@ infos.read(directory, segmentFileName); if (readOnly) - return new ReadOnlyDirectoryReader(directory, infos, deletionPolicy, closeDirectory); + return new ReadOnlyDirectoryReader(directory, infos, deletionPolicy); else - return new DirectoryReader(directory, infos, deletionPolicy, closeDirectory, false); + return new DirectoryReader(directory, infos, deletionPolicy, false); } }; - IndexReader reader = null; - try { - reader = (IndexReader) finder.run(commit); - } finally { - // We passed false above for closeDirectory so that - // the directory would not be closed before we were - // done retrying, so at this point if we truly failed - // to open a reader, which means an exception is being - // thrown, then close the directory now: - if (reader == null && closeDirectory) { - try { - directory.close(); - } catch (IOException ioe) { - // suppress, so we keep throwing original failure - // from opening the reader - } - } - } - - return reader; + return (IndexReader) finder.run(commit); } /** Construct reading the named set of readers. */ - DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean closeDirectory, boolean readOnly) throws IOException { + DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean readOnly) throws IOException { this.directory = directory; this.readOnly = readOnly; - this.closeDirectory = closeDirectory; this.segmentInfos = sis; this.deletionPolicy = deletionPolicy; @@ -147,7 +125,6 @@ DirectoryReader(IndexWriter writer, SegmentInfos infos) throws IOException { this.directory = writer.getDirectory(); this.readOnly = true; - this.closeDirectory = false; this.segmentInfos = infos; if (!readOnly) { // We assume that this segments_N was previously @@ -198,11 +175,10 @@ } /** This contructor is only used for {@link #reopen()} */ - DirectoryReader(Directory directory, SegmentInfos infos, boolean closeDirectory, SegmentReader[] oldReaders, int[] oldStarts, + DirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache, boolean readOnly, boolean doClone) throws IOException { this.directory = directory; this.readOnly = readOnly; - this.closeDirectory = closeDirectory; this.segmentInfos = infos; if (!readOnly) { // We assume that this segments_N was previously @@ -347,7 +323,6 @@ DirectoryReader newReader = doReopen((SegmentInfos) segmentInfos.clone(), true, openReadOnly); if (this != newReader) { - newReader.closeDirectory = closeDirectory; newReader.deletionPolicy = deletionPolicy; } newReader.writer = writer; @@ -454,45 +429,15 @@ } }; - DirectoryReader reader = null; - - /* TODO: Remove this in 3.0 - the directory is then - * no longer owned by the IndexReader and must not be - * closed. - * While trying to reopen, we temporarily mark our - * closeDirectory as false. This way any exceptions hit - * partway while opening the reader, which is expected - * eg if writer is committing, won't close our - * directory. We restore this value below: - */ - final boolean myCloseDirectory = closeDirectory; // @deprectated - closeDirectory = false; - - try { - reader = (DirectoryReader) finder.run(commit); - } finally { - if (myCloseDirectory) { - assert directory instanceof FSDirectory; - // Restore my closeDirectory - closeDirectory = true; - if (reader != null && reader != this) { - // Success, and a new reader was actually opened - reader.closeDirectory = true; - // Clone the directory - reader.directory = FSDirectory.getDirectory(((FSDirectory) directory).getFile()); - } - } - } - - return reader; + return (DirectoryReader) finder.run(commit); } private synchronized DirectoryReader doReopen(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException { DirectoryReader reader; if (openReadOnly) { - reader = new ReadOnlyDirectoryReader(directory, infos, closeDirectory, subReaders, starts, normsCache, doClone); + reader = new ReadOnlyDirectoryReader(directory, infos, subReaders, starts, normsCache, doClone); } else { - reader = new DirectoryReader(directory, infos, closeDirectory, subReaders, starts, normsCache, false, doClone); + reader = new DirectoryReader(directory, infos, subReaders, starts, normsCache, false, doClone); } reader.setDisableFakeNorms(getDisableFakeNorms()); return reader; @@ -870,9 +815,6 @@ protected synchronized void doClose() throws IOException { for (int i = 0; i < subReaders.length; i++) subReaders[i].decRef(); - - if (closeDirectory) - directory.close(); } public Collection getFieldNames (IndexReader.FieldOption fieldNames) { Index: src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- src/java/org/apache/lucene/index/IndexReader.java (revision 782754) +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -199,7 +199,89 @@ throw new AlreadyClosedException("this IndexReader is closed"); } } + + /** + * This class keeps track of closing the underlying directory. It is used to wrap + * index readers, that are created using FSDirectory.getDirectory()/open(). + * @deprecated This helper class is removed with all String/File open() methods in 3.0 + */ + private static final class DirectoryOwningIndexReader extends FilterIndexReader { + DirectoryOwningIndexReader(final IndexReader in) { + this(in, new RefCounter()); + } + + private DirectoryOwningIndexReader(final IndexReader in, final RefCounter refCount) { + super(in); + this.refCount = refCount; + refCount.incRef(); + } + + public synchronized IndexReader reopen() throws CorruptIndexException, IOException { + ensureOpen(); + final IndexReader r = in.reopen(); + if (r != in) + return new DirectoryOwningIndexReader(r, refCount); + return this; + } + + public synchronized IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException { + ensureOpen(); + final IndexReader r = in.reopen(openReadOnly); + if (r != in) + return new DirectoryOwningIndexReader(r, refCount); + return this; + } + + public synchronized IndexReader reopen(final IndexCommit commit) throws CorruptIndexException, IOException { + ensureOpen(); + final IndexReader r = in.reopen(commit); + if (r != in) + return new DirectoryOwningIndexReader(r, refCount); + return this; + } + + public synchronized Object clone() { + ensureOpen(); + return new DirectoryOwningIndexReader((IndexReader) in.clone(), refCount); + } + + public synchronized IndexReader clone(boolean openReadOnly) throws CorruptIndexException, IOException { + ensureOpen(); + return new DirectoryOwningIndexReader(in.clone(openReadOnly), refCount); + } + + protected void doClose() throws IOException { + try { + super.doClose(); + } finally { + if (refCount.decRef() == 0) { + directory().close(); + } + } + } + + private final RefCounter refCount; + + /** This class contains the ref counter, that is passed to each instance after cloning/reopening, + * and is global to all DirectoryOwningIndexReader derived from the original one. + * In Java 1.5, I would use an j.u.concurrent.atomic.AtomicInteger, which is equal to this one. + */ + private static final class RefCounter { + private int c = 0; + + public synchronized int incRef() { + return ++c; + } + + public synchronized int decRef() { + return --c; + } + + } + + } + /** Returns a read/write IndexReader reading the index in an FSDirectory in the named * path. * @throws CorruptIndexException if the index is corrupt @@ -208,7 +290,7 @@ * Use {@link #open(Directory, boolean)} instead * @param path the path to the index directory */ public static IndexReader open(String path) throws CorruptIndexException, IOException { - return open(FSDirectory.getDirectory(path), true, null, null, false); + return new DirectoryOwningIndexReader(open(FSDirectory.getDirectory(path), null, null, false)); } /** Returns an IndexReader reading the index in an @@ -225,7 +307,7 @@ * Use {@link #open(Directory, boolean)} instead */ public static IndexReader open(String path, boolean readOnly) throws CorruptIndexException, IOException { - return open(FSDirectory.getDirectory(path), true, null, null, readOnly); + return new DirectoryOwningIndexReader(open(FSDirectory.getDirectory(path), null, null, readOnly)); } /** Returns a read/write IndexReader reading the index in an FSDirectory in the named @@ -237,7 +319,7 @@ * Use {@link #open(Directory, boolean)} instead */ public static IndexReader open(File path) throws CorruptIndexException, IOException { - return open(FSDirectory.getDirectory(path), true, null, null, false); + return new DirectoryOwningIndexReader(open(FSDirectory.getDirectory(path), null, null, false)); } /** Returns an IndexReader reading the index in an @@ -254,7 +336,7 @@ * Use {@link #open(Directory, boolean)} instead */ public static IndexReader open(File path, boolean readOnly) throws CorruptIndexException, IOException { - return open(FSDirectory.getDirectory(path), true, null, null, readOnly); + return new DirectoryOwningIndexReader(open(FSDirectory.getDirectory(path), null, null, readOnly)); } /** Returns a read/write IndexReader reading the index in @@ -266,7 +348,7 @@ * Use {@link #open(Directory, boolean)} instead */ public static IndexReader open(final Directory directory) throws CorruptIndexException, IOException { - return open(directory, false, null, null, false); + return open(directory, null, null, false); } /** Returns an IndexReader reading the index in the given @@ -280,7 +362,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final Directory directory, boolean readOnly) throws CorruptIndexException, IOException { - return open(directory, false, null, null, readOnly); + return open(directory, null, null, readOnly); } /** Expert: returns a read/write IndexReader reading the index in the given @@ -292,7 +374,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final IndexCommit commit) throws CorruptIndexException, IOException { - return open(commit.getDirectory(), false, null, commit, false); + return open(commit.getDirectory(), null, commit, false); } /** Expert: returns an IndexReader reading the index in the given @@ -306,7 +388,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final IndexCommit commit, boolean readOnly) throws CorruptIndexException, IOException { - return open(commit.getDirectory(), false, null, commit, readOnly); + return open(commit.getDirectory(), null, commit, readOnly); } /** Expert: returns a read/write IndexReader reading the index in the given @@ -321,7 +403,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final Directory directory, IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { - return open(directory, false, deletionPolicy, null, false); + return open(directory, deletionPolicy, null, false); } /** Expert: returns an IndexReader reading the index in @@ -339,7 +421,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final Directory directory, IndexDeletionPolicy deletionPolicy, boolean readOnly) throws CorruptIndexException, IOException { - return open(directory, false, deletionPolicy, null, readOnly); + return open(directory, deletionPolicy, null, readOnly); } /** Expert: returns a read/write IndexReader reading the index in the given @@ -357,7 +439,7 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final IndexCommit commit, IndexDeletionPolicy deletionPolicy) throws CorruptIndexException, IOException { - return open(commit.getDirectory(), false, deletionPolicy, commit, false); + return open(commit.getDirectory(), deletionPolicy, commit, false); } /** Expert: returns an IndexReader reading the index in @@ -377,11 +459,11 @@ * @throws IOException if there is a low-level IO error */ public static IndexReader open(final IndexCommit commit, IndexDeletionPolicy deletionPolicy, boolean readOnly) throws CorruptIndexException, IOException { - return open(commit.getDirectory(), false, deletionPolicy, commit, readOnly); + return open(commit.getDirectory(), deletionPolicy, commit, readOnly); } - private static IndexReader open(final Directory directory, final boolean closeDirectory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { - return DirectoryReader.open(directory, closeDirectory, deletionPolicy, commit, readOnly); + private static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly) throws CorruptIndexException, IOException { + return DirectoryReader.open(directory, deletionPolicy, commit, readOnly); } /** @@ -577,9 +659,11 @@ */ public static long getCurrentVersion(File directory) throws CorruptIndexException, IOException { Directory dir = FSDirectory.getDirectory(directory); - long version = getCurrentVersion(dir); - dir.close(); - return version; + try { + return getCurrentVersion(dir); + } finally { + dir.close(); + } } /** @@ -1196,9 +1280,11 @@ */ public static boolean isLocked(String directory) throws IOException { Directory dir = FSDirectory.getDirectory(directory); - boolean result = isLocked(dir); - dir.close(); - return result; + try { + return isLocked(dir); + } finally { + dir.close(); + } } /** Index: src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java =================================================================== --- src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java (revision 782754) +++ src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java (working copy) @@ -23,12 +23,12 @@ import java.util.Map; class ReadOnlyDirectoryReader extends DirectoryReader { - ReadOnlyDirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean closeDirectory) throws IOException { - super(directory, sis, deletionPolicy, closeDirectory, true); + ReadOnlyDirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy) throws IOException { + super(directory, sis, deletionPolicy, true); } - ReadOnlyDirectoryReader(Directory directory, SegmentInfos infos, boolean closeDirectory, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache, boolean doClone) throws IOException { - super(directory, infos, closeDirectory, oldReaders, oldStarts, oldNormsCache, true, doClone); + ReadOnlyDirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache, boolean doClone) throws IOException { + super(directory, infos, oldReaders, oldStarts, oldNormsCache, true, doClone); } ReadOnlyDirectoryReader(IndexWriter writer, SegmentInfos infos) throws IOException {