Index: lucene/contrib/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestDirectoryTaxonomyReader.java =================================================================== --- lucene/contrib/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestDirectoryTaxonomyReader.java (revision 1232874) +++ lucene/contrib/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestDirectoryTaxonomyReader.java (working copy) @@ -11,6 +11,7 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.LuceneTestCase; import org.junit.Test; @@ -178,4 +179,28 @@ } } + @Test + public void testRefreshAndRefCount() throws Exception { + Directory dir = new RAMDirectory(); // no need for random directories here + + DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(dir); + taxoWriter.addCategory(new CategoryPath("a")); + taxoWriter.commit(); + + DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(dir); + assertEquals(1, taxoReader.getRefCount()); + + taxoReader.incRef(); + assertEquals(2, taxoReader.getRefCount()); + + taxoWriter.addCategory(new CategoryPath("a", "b")); + taxoWriter.commit(); + taxoReader.refresh(); + assertEquals(2, taxoReader.getRefCount()); + + taxoWriter.close(); + taxoReader.close(); + dir.close(); + } + } Index: lucene/contrib/facet/src/java/org/apache/lucene/facet/taxonomy/directory/DirectoryTaxonomyReader.java =================================================================== --- lucene/contrib/facet/src/java/org/apache/lucene/facet/taxonomy/directory/DirectoryTaxonomyReader.java (revision 1232874) +++ lucene/contrib/facet/src/java/org/apache/lucene/facet/taxonomy/directory/DirectoryTaxonomyReader.java (working copy) @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; @@ -96,6 +97,9 @@ private volatile boolean closed = false; + // set refCount to 1 at start + private final AtomicInteger refCount = new AtomicInteger(1); + /** * Open for reading a taxonomy stored in a given {@link Directory}. * @param directory @@ -126,7 +130,7 @@ * @throws AlreadyClosedException if this IndexReader is closed */ protected final void ensureOpen() throws AlreadyClosedException { - if (indexReader.getRefCount() <= 0) { + if (getRefCount() <= 0) { throw new AlreadyClosedException("this TaxonomyReader is closed"); } } @@ -408,8 +412,12 @@ public void close() throws IOException { if (!closed) { - decRef(); - closed = true; + synchronized (this) { + if (!closed) { + decRef(); + closed = true; + } + } } } @@ -548,27 +556,31 @@ } /** - * Expert: decreases the refCount of this TaxonomyReader instance. - * If the refCount drops to 0, then pending changes (if any) are - * committed to the taxonomy index and this reader is closed. - * @throws IOException + * Expert: decreases the refCount of this TaxonomyReader instance. If the + * refCount drops to 0, then this reader is closed. */ public void decRef() throws IOException { ensureOpen(); - if (indexReader.getRefCount() == 1) { - // Do not decRef the indexReader - doClose does it by calling reader.close() - doClose(); - } else { - indexReader.decRef(); + final int rc = refCount.decrementAndGet(); + if (rc == 0) { + boolean success = false; + try { + doClose(); + success = true; + } finally { + if (!success) { + // Put reference back on failure + refCount.incrementAndGet(); + } + } + } else if (rc < 0) { + throw new IllegalStateException("too many decRef calls: refCount is " + rc + " after decrement"); } } - /** - * Expert: returns the current refCount for this taxonomy reader - */ + /** Expert: returns the current refCount for this taxonomy reader */ public int getRefCount() { - ensureOpen(); - return this.indexReader.getRefCount(); + return refCount.get(); } /** @@ -580,6 +592,6 @@ */ public void incRef() { ensureOpen(); - this.indexReader.incRef(); + refCount.incrementAndGet(); } } Index: lucene/contrib/CHANGES.txt =================================================================== --- lucene/contrib/CHANGES.txt (revision 1232874) +++ lucene/contrib/CHANGES.txt (working copy) @@ -97,6 +97,10 @@ * LUCENE-3697: SimpleBoundaryScanner does not work well when highlighting at the beginning of the text. (Shay Banon via Koji Sekiguchi) + * LUCENE-3703: Calling DirectoryTaxonomyReader.refresh() could mess up + reference counting (e.g. if one called incRef/decRef by himself). + (Doron Cohen, Shai Erera) + Documentation * LUCENE-3599: Javadocs for DistanceUtils.haversine() were incorrectly