LUCENE-3476: SearcherManager misses to close IR if manager is closed during reopen

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1177940 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Simon Willnauer 2011-10-01 08:10:21 +00:00
parent b4ff06f88e
commit d514a4ac75
2 changed files with 93 additions and 3 deletions

View File

@ -152,7 +152,15 @@ public class SearcherManager implements Closeable {
}
}
}
swapSearcher(newSearcher);
boolean success = false;
try {
swapSearcher(newSearcher);
success = true;
} finally {
if (!success) {
release(newSearcher);
}
}
return true;
} else {
return false;
@ -204,7 +212,12 @@ public class SearcherManager implements Closeable {
* affected, and they should still call {@link #release}
* after they are done. */
@Override
public void close() throws IOException {
swapSearcher(null);
public synchronized void close() throws IOException {
if (currentSearcher != null) {
// make sure we can call this more than once
// closeable javadoc says:
// if this is already closed then invoking this method has no effect.
swapSearcher(null);
}
}
}

View File

@ -18,10 +18,17 @@ package org.apache.lucene.search;
*/
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.ThreadedIndexingAndSearchingTestCase;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util._TestUtil;
public class TestSearcherManager extends ThreadedIndexingAndSearchingTestCase {
@ -110,4 +117,74 @@ public class TestSearcherManager extends ThreadedIndexingAndSearchingTestCase {
}
mgr.close();
}
public void testIntermediateClose() throws IOException, InterruptedException {
Directory dir = newDirectory();
IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
TEST_VERSION_CURRENT, new MockAnalyzer(random)));
writer.addDocument(new Document());
writer.commit();
final CountDownLatch awaitEnterWarm = new CountDownLatch(1);
final CountDownLatch awaitClose = new CountDownLatch(1);
final SearcherManager searcherManager = new SearcherManager(dir,
new SearcherWarmer() {
@Override
public void warm(IndexSearcher s) throws IOException {
try {
awaitEnterWarm.countDown();
awaitClose.await();
} catch (InterruptedException e) {
//
}
}
});
IndexSearcher searcher = searcherManager.acquire();
try {
assertEquals(1, searcher.getIndexReader().numDocs());
} finally {
searcherManager.release(searcher);
}
writer.addDocument(new Document());
writer.commit();
final AtomicBoolean success = new AtomicBoolean(false);
final AtomicBoolean triedReopen = new AtomicBoolean(false);
final Throwable[] exc = new Throwable[1];
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
triedReopen.set(true);
searcherManager.maybeReopen();
success.set(true);
} catch (AlreadyClosedException e) {
// expected
} catch (Throwable e) {
exc[0] = e;
// use success as the barrier here to make sure we see the write
success.set(false);
}
}
});
thread.start();
awaitEnterWarm.await();
for (int i = 0; i < 2; i++) {
searcherManager.close();
}
awaitClose.countDown();
thread.join();
try {
searcherManager.acquire();
fail("already closed");
} catch (AlreadyClosedException ex) {
// expected
}
assertFalse(success.get());
assertTrue(triedReopen.get());
assertNull("" + exc[0], exc[0]);
writer.close();
dir.close();
}
}