mirror of https://github.com/apache/lucene.git
add test case to ensure SearchManager can handle concurrent close, refresh, searching and IndexWriter closing
This commit is contained in:
parent
3e64a97597
commit
f0963b3b4f
|
@ -26,6 +26,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.lucene.analysis.MockAnalyzer;
|
||||
import org.apache.lucene.document.Document;
|
||||
|
@ -43,6 +44,7 @@ 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.LineFileDocs;
|
||||
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.apache.lucene.util.NamedThreadFactory;
|
||||
|
@ -533,4 +535,144 @@ public class TestSearcherManager extends ThreadedIndexingAndSearchingTestCase {
|
|||
sm.close();
|
||||
dir.close();
|
||||
}
|
||||
|
||||
public void testConcurrentIndexCloseSearchAndRefresh() throws Exception {
|
||||
final Directory dir = newFSDirectory(createTempDir());
|
||||
AtomicReference<IndexWriter> writerRef = new AtomicReference<>();
|
||||
writerRef.set(new IndexWriter(dir, newIndexWriterConfig()));
|
||||
|
||||
AtomicReference<SearcherManager> mgrRef = new AtomicReference<>();
|
||||
mgrRef.set(new SearcherManager(writerRef.get(), null));
|
||||
final AtomicBoolean stop = new AtomicBoolean();
|
||||
|
||||
Thread indexThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
LineFileDocs docs = new LineFileDocs(random());
|
||||
long runTimeSec = TEST_NIGHTLY ? atLeast(10) : atLeast(2);
|
||||
long endTime = System.nanoTime() + runTimeSec * 1000000000;
|
||||
while (System.nanoTime() < endTime) {
|
||||
IndexWriter w = writerRef.get();
|
||||
w.addDocument(docs.nextDoc());
|
||||
if (random().nextInt(1000) == 17) {
|
||||
if (random().nextBoolean()) {
|
||||
w.close();
|
||||
} else {
|
||||
w.rollback();
|
||||
}
|
||||
writerRef.set(new IndexWriter(dir, newIndexWriterConfig()));
|
||||
}
|
||||
}
|
||||
docs.close();
|
||||
stop.set(true);
|
||||
if (VERBOSE) {
|
||||
System.out.println("TEST: index count=" + writerRef.get().maxDoc());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread searchThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long totCount = 0;
|
||||
while (stop.get() == false) {
|
||||
SearcherManager mgr = mgrRef.get();
|
||||
if (mgr != null) {
|
||||
IndexSearcher searcher;
|
||||
try {
|
||||
searcher = mgr.acquire();
|
||||
} catch (AlreadyClosedException ace) {
|
||||
// ok
|
||||
continue;
|
||||
}
|
||||
totCount += searcher.getIndexReader().maxDoc();
|
||||
mgr.release(searcher);
|
||||
}
|
||||
}
|
||||
if (VERBOSE) {
|
||||
System.out.println("TEST: search totCount=" + totCount);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread refreshThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int refreshCount = 0;
|
||||
int aceCount = 0;
|
||||
while (stop.get() == false) {
|
||||
SearcherManager mgr = mgrRef.get();
|
||||
if (mgr != null) {
|
||||
refreshCount++;
|
||||
try {
|
||||
mgr.maybeRefreshBlocking();
|
||||
} catch (AlreadyClosedException ace) {
|
||||
// ok
|
||||
aceCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VERBOSE) {
|
||||
System.out.println("TEST: refresh count=" + refreshCount + " aceCount=" + aceCount);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread closeThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int closeCount = 0;
|
||||
int aceCount = 0;
|
||||
while (stop.get() == false) {
|
||||
SearcherManager mgr = mgrRef.get();
|
||||
assert mgr != null;
|
||||
mgr.close();
|
||||
closeCount++;
|
||||
while (stop.get() == false) {
|
||||
try {
|
||||
mgrRef.set(new SearcherManager(writerRef.get(), null));
|
||||
break;
|
||||
} catch (AlreadyClosedException ace) {
|
||||
// ok
|
||||
aceCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VERBOSE) {
|
||||
System.out.println("TEST: close count=" + closeCount + " aceCount=" + aceCount);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
indexThread.start();
|
||||
searchThread.start();
|
||||
refreshThread.start();
|
||||
closeThread.start();
|
||||
|
||||
indexThread.join();
|
||||
searchThread.join();
|
||||
refreshThread.join();
|
||||
closeThread.join();
|
||||
|
||||
mgrRef.get().close();
|
||||
writerRef.get().close();
|
||||
dir.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -838,7 +838,7 @@ public class MockDirectoryWrapper extends BaseDirectoryWrapper {
|
|||
}
|
||||
// RuntimeException instead of IOException because
|
||||
// super() does not throw IOException currently:
|
||||
throw new RuntimeException("MockDirectoryWrapper: cannot close: there are still open files: " + openFiles, cause);
|
||||
throw new RuntimeException("MockDirectoryWrapper: cannot close: there are still " + openFiles.size() + " open files: " + openFiles, cause);
|
||||
}
|
||||
if (openLocks.size() > 0) {
|
||||
Exception cause = null;
|
||||
|
|
Loading…
Reference in New Issue