blob: 62e732ff976360ab9e05966bb107523300d55098 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.index;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
public class TestIndexWriterNRTIsCurrent extends LuceneTestCase {
public static class ReaderHolder {
volatile DirectoryReader reader;
volatile boolean stop = false;
}
public void testIsCurrentWithThreads() throws
IOException, InterruptedException {
Directory dir = newDirectory();
IndexWriterConfig conf = newIndexWriterConfig(new MockAnalyzer(random()));
IndexWriter writer = new IndexWriter(dir, conf);
ReaderHolder holder = new ReaderHolder();
int numReaderThreads = TEST_NIGHTLY ? TestUtil.nextInt(random(), 2, 5) : 2;
ReaderThread[] threads = new ReaderThread[numReaderThreads];
final CountDownLatch latch = new CountDownLatch(1);
WriterThread writerThread = new WriterThread(holder, writer,
atLeast(500), random(), latch);
for (int i = 0; i < threads.length; i++) {
threads[i] = new ReaderThread(holder, latch);
threads[i].start();
}
writerThread.start();
writerThread.join();
boolean failed = writerThread.failed != null;
if (failed)
writerThread.failed.printStackTrace();
for (int i = 0; i < threads.length; i++) {
threads[i].join();
if (threads[i].failed != null) {
threads[i].failed.printStackTrace();
failed = true;
}
}
assertFalse(failed);
writer.close();
dir.close();
}
public static class WriterThread extends Thread {
private final ReaderHolder holder;
private final IndexWriter writer;
private final int numOps;
private boolean countdown = true;
private final CountDownLatch latch;
Throwable failed;
WriterThread(ReaderHolder holder, IndexWriter writer, int numOps,
Random random, CountDownLatch latch) {
super();
this.holder = holder;
this.writer = writer;
this.numOps = numOps;
this.latch = latch;
}
@Override
public void run() {
DirectoryReader currentReader = null;
Random random = LuceneTestCase.random();
try {
Document doc = new Document();
doc.add(new TextField("id", "1", Field.Store.NO));
writer.addDocument(doc);
holder.reader = currentReader = writer.getReader();
Term term = new Term("id");
for (int i = 0; i < numOps && !holder.stop; i++) {
float nextOp = random.nextFloat();
if (nextOp < 0.3) {
term.set("id", new BytesRef("1"));
writer.updateDocument(term, doc);
} else if (nextOp < 0.5) {
writer.addDocument(doc);
} else {
term.set("id", new BytesRef("1"));
writer.deleteDocuments(term);
}
if (holder.reader != currentReader) {
holder.reader = currentReader;
if (countdown) {
countdown = false;
latch.countDown();
}
}
if (random.nextBoolean()) {
writer.commit();
final DirectoryReader newReader = DirectoryReader
.openIfChanged(currentReader);
if (newReader != null) {
currentReader.decRef();
currentReader = newReader;
}
if (currentReader.numDocs() == 0) {
writer.addDocument(doc);
}
}
}
} catch (Throwable e) {
failed = e;
} finally {
holder.reader = null;
if (countdown) {
latch.countDown();
}
if (currentReader != null) {
try {
currentReader.decRef();
} catch (IOException e) {
}
}
}
if (VERBOSE) {
System.out.println("writer stopped - forced by reader: " + holder.stop);
}
}
}
public static final class ReaderThread extends Thread {
private final ReaderHolder holder;
private final CountDownLatch latch;
Throwable failed;
ReaderThread(ReaderHolder holder, CountDownLatch latch) {
super();
this.holder = holder;
this.latch = latch;
}
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
failed = e;
return;
}
DirectoryReader reader;
while ((reader = holder.reader) != null) {
if (reader.tryIncRef()) {
try {
boolean current = reader.isCurrent();
if (VERBOSE) {
System.out.println("Thread: " + Thread.currentThread() + " Reader: " + reader + " isCurrent:" + current);
}
assertFalse(current);
} catch (Throwable e) {
if (VERBOSE) {
System.out.println("FAILED Thread: " + Thread.currentThread() + " Reader: " + reader + " isCurrent: false");
}
failed = e;
holder.stop = true;
return;
} finally {
try {
reader.decRef();
} catch (IOException e) {
if (failed == null) {
failed = e;
}
}
}
}
}
}
}
}