Index: src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- src/java/org/apache/lucene/index/DirectoryReader.java (revision 890439) +++ src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -32,7 +32,6 @@ import org.apache.lucene.document.Document; import org.apache.lucene.document.FieldSelector; import org.apache.lucene.search.Similarity; -import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; import org.apache.lucene.store.Lock; import org.apache.lucene.store.LockObtainFailedException; @@ -379,10 +378,6 @@ throw new IllegalArgumentException("a reader obtained from IndexWriter.getReader() cannot currently accept a commit"); } - if (!writer.isOpen(true)) { - throw new AlreadyClosedException("cannot reopen: the IndexWriter this reader was obtained from is now closed"); - } - // TODO: right now we *always* make a new reader; in // the future we could have write make some effort to // detect that no changes have occurred Index: src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- src/java/org/apache/lucene/index/IndexReader.java (revision 890439) +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; /** IndexReader is an abstract class, providing an interface for accessing an index. Search of an index is done entirely through this abstract interface, @@ -116,13 +117,13 @@ private boolean closed; protected boolean hasChanges; - private int refCount; + private final AtomicInteger refCount = new AtomicInteger(); static int DEFAULT_TERMS_INDEX_DIVISOR = 1; /** Expert: returns the current refCount for this reader */ - public synchronized int getRefCount() { - return refCount; + public int getRefCount() { + return refCount.get(); } /** @@ -139,41 +140,48 @@ * * @see #decRef */ - public synchronized void incRef() { - assert refCount > 0; + public void incRef() { ensureOpen(); - refCount++; + refCount.incrementAndGet(); } /** * Expert: decreases the refCount of this IndexReader * instance. If the refCount drops to 0, then pending * changes (if any) are committed to the index and this - * reader is closed. - * + * reader is closed. If an exception is hit, the refCount + * is unchanged. + * * @throws IOException in case an IOException occurs in commit() or doClose() * * @see #incRef */ - public synchronized void decRef() throws IOException { - assert refCount > 0; + public void decRef() throws IOException { ensureOpen(); - if (refCount == 1) { - commit(); - doClose(); + if (refCount.getAndDecrement() == 1) { + boolean success = false; + try { + commit(); + doClose(); + success = true; + } finally { + if (!success) { + // Put reference back on failure + refCount.incrementAndGet(); + } + } } - refCount--; } protected IndexReader() { - refCount = 1; + refCount.set(1); } /** * @throws AlreadyClosedException if this IndexReader is closed */ protected final void ensureOpen() throws AlreadyClosedException { - if (refCount <= 0) { + if (refCount.get() <= 0) { throw new AlreadyClosedException("this IndexReader is closed"); } } Index: src/java/org/apache/lucene/index/IndexWriter.java =================================================================== --- src/java/org/apache/lucene/index/IndexWriter.java (revision 890439) +++ src/java/org/apache/lucene/index/IndexWriter.java (working copy) @@ -42,6 +42,7 @@ import java.util.LinkedList; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; /** An IndexWriter creates and maintains an index. @@ -272,8 +273,8 @@ private int termIndexInterval = DEFAULT_TERM_INDEX_INTERVAL; - private boolean closed; - private boolean closing; + final private AtomicBoolean closed = new AtomicBoolean(); + final private AtomicBoolean closing = new AtomicBoolean(); // Holds all SegmentInfo instances currently involved in // merges @@ -386,6 +387,9 @@ * loading a TermInfo. The default value is 1. Set this * to -1 to skip loading the terms index entirely. */ public IndexReader getReader(int termInfosIndexDivisor) throws IOException { + + ensureOpen(); + if (infoStream != null) { message("flush at getReader"); } @@ -703,23 +707,19 @@ notifyAll(); } - synchronized final boolean isOpen(boolean includePendingClose) { - return !(closed || (includePendingClose && closing)); - } - /** * Used internally to throw an {@link * AlreadyClosedException} if this IndexWriter has been * closed. * @throws AlreadyClosedException if this IndexWriter is */ - protected synchronized final void ensureOpen(boolean includePendingClose) throws AlreadyClosedException { - if (!isOpen(includePendingClose)) { + protected final void ensureOpen(boolean includePendingClose) throws AlreadyClosedException { + if (closed.get() || (includePendingClose && closing.get())) { throw new AlreadyClosedException("this IndexWriter is closed"); } } - protected synchronized final void ensureOpen() throws AlreadyClosedException { + protected final void ensureOpen() throws AlreadyClosedException { ensureOpen(true); } @@ -1630,9 +1630,9 @@ // another thread finishes closing synchronized private boolean shouldClose() { while(true) { - if (!closed) { - if (!closing) { - closing = true; + if (!closed.get()) { + if (!closing.get()) { + closing.set(true); return true; } else { // Another thread is presently trying to close; @@ -1693,16 +1693,14 @@ writeLock.release(); // release write lock writeLock = null; } - synchronized(this) { - closed = true; - } + closed.set(true); } catch (OutOfMemoryError oom) { handleOOM(oom, "closeInternal"); } finally { synchronized(this) { - closing = false; + closing.set(false); notifyAll(); - if (!closed) { + if (!closed.get()) { if (docWriter != null) docWriter.resumeAllThreads(); if (infoStream != null) @@ -2759,7 +2757,7 @@ synchronized(this) { if (!success) { docWriter.resumeAllThreads(); - closing = false; + closing.set(false); notifyAll(); if (infoStream != null) message("hit exception during rollback"); @@ -2906,7 +2904,7 @@ releaseWrite(); } - private void blockAddIndexes(boolean includePendingClose) { + private void blockAddIndexes() { acquireRead(); @@ -2915,7 +2913,7 @@ // Make sure we are still open since we could have // waited quite a while for last addIndexes to finish - ensureOpen(includePendingClose); + ensureOpen(false); success = true; } finally { if (!success) @@ -3937,7 +3935,7 @@ // This merge (and, generally, any change to the // segments) may now enable new merges, so we call // merge policy & update pending merges. - if (success && !merge.isAborted() && !closed && !closing) + if (success && !merge.isAborted() && !closed.get() && !closing.get()) updatePendingMerges(merge.maxNumSegmentsOptimize, merge.optimize); } } @@ -4588,7 +4586,7 @@ // Wait for any running addIndexes to complete // first, then block any from running until we've // copied the segmentInfos we intend to sync: - blockAddIndexes(false); + blockAddIndexes(); // On commit the segmentInfos must never // reference a segment in another directory: @@ -4881,7 +4879,7 @@ } } - synchronized boolean isClosed() { - return closed; + boolean isClosed() { + return closed.get(); } }