fix several threading issues

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@328151 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Daniel Naber 2005-10-24 20:54:45 +00:00
parent 8559a28c6e
commit 0c26106b36
1 changed files with 82 additions and 70 deletions

View File

@ -18,6 +18,7 @@ package org.apache.lucene.index;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.EmptyStackException;
import java.util.Random; import java.util.Random;
import java.util.Stack; import java.util.Stack;
@ -33,15 +34,13 @@ import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.store.RAMDirectory;
/** /**
* Tests for the "Index" class, including accesses from two threads at the * Tests for the "IndexModifier" class, including accesses from two threads at the
* same time. * same time.
* *
* @author Daniel Naber * @author Daniel Naber
*/ */
public class TestIndexModifier extends TestCase { public class TestIndexModifier extends TestCase {
private final int ITERATIONS = 500; // iterations of thread test
private int docCount = 0; private int docCount = 0;
private final Term allDocTerm = new Term("all", "x"); private final Term allDocTerm = new Term("all", "x");
@ -138,7 +137,7 @@ public class TestIndexModifier extends TestCase {
} }
private void testIndexInternal(int maxWait) throws IOException { private void testIndexInternal(int maxWait) throws IOException {
boolean create = true; final boolean create = true;
//Directory rd = new RAMDirectory(); //Directory rd = new RAMDirectory();
// work on disk to make sure potential lock problems are tested: // work on disk to make sure potential lock problems are tested:
String tempDir = System.getProperty("java.io.tmpdir"); String tempDir = System.getProperty("java.io.tmpdir");
@ -146,16 +145,18 @@ public class TestIndexModifier extends TestCase {
throw new IOException("java.io.tmpdir undefined, cannot run test"); throw new IOException("java.io.tmpdir undefined, cannot run test");
File indexDir = new File(tempDir, "lucenetestindex"); File indexDir = new File(tempDir, "lucenetestindex");
Directory rd = FSDirectory.getDirectory(indexDir, create); Directory rd = FSDirectory.getDirectory(indexDir, create);
IndexThread.id = 0;
IndexThread.idStack.clear();
IndexModifier index = new IndexModifier(rd, new StandardAnalyzer(), create); IndexModifier index = new IndexModifier(rd, new StandardAnalyzer(), create);
IndexThread thread1 = new IndexThread(index, maxWait); IndexThread thread1 = new IndexThread(index, maxWait, 1);
thread1.start(); thread1.start();
IndexThread thread2 = new IndexThread(index, maxWait); IndexThread thread2 = new IndexThread(index, maxWait, 2);
thread2.start(); thread2.start();
while(thread1.isAlive() || thread2.isAlive()) { while(thread1.isAlive() || thread2.isAlive()) {
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); throw new RuntimeException(e);
} }
} }
index.optimize(); index.optimize();
@ -181,12 +182,6 @@ public class TestIndexModifier extends TestCase {
dir.delete(); dir.delete();
} }
private int id = 0;
private Stack idStack = new Stack();
// TODO: test case is not reproducible despite pseudo-random numbers
// used for anything:
private Random random = new Random(101); // constant seed for reproducability
private class PowerIndex extends IndexModifier { private class PowerIndex extends IndexModifier {
public PowerIndex(Directory dir, Analyzer analyzer, boolean create) throws IOException { public PowerIndex(Directory dir, Analyzer analyzer, boolean create) throws IOException {
super(dir, analyzer, create); super(dir, analyzer, create);
@ -200,71 +195,88 @@ public class TestIndexModifier extends TestCase {
} }
} }
private class IndexThread extends Thread { }
private int maxWait = 10; class IndexThread extends Thread {
private IndexModifier index;
private int added = 0;
private int deleted = 0;
IndexThread(IndexModifier index, int maxWait) { private final static int ITERATIONS = 500; // iterations of thread test
this.index = index;
this.maxWait = maxWait;
id = 0;
idStack.clear();
}
public void run() { static int id = 0;
try { static Stack idStack = new Stack();
for(int i = 0; i < ITERATIONS; i++) {
int rand = random.nextInt(101); int added = 0;
if (rand < 5) { int deleted = 0;
index.optimize();
} else if (rand < 60) { private int maxWait = 10;
Document doc = getDocument(); private IndexModifier index;
//System.out.println("add doc id=" + doc.get("id")); private int threadNumber;
index.addDocument(doc); private Random random;
idStack.push(doc.get("id"));
added++; IndexThread(IndexModifier index, int maxWait, int threadNumber) {
} else { this.index = index;
if (idStack.size() == 0) { this.maxWait = maxWait;
// not enough docs in index, let's wait for next chance this.threadNumber = threadNumber;
} else { // TODO: test case is not reproducible despite pseudo-random numbers:
// we just delete the last document added and remove it random = new Random(101+threadNumber); // constant seed for better reproducability
// from the id stack so that it won't be removed twice: }
String delId = (String)idStack.pop();
//System.out.println("delete doc id = " + delId); public void run() {
index.delete(new Term("id", new Integer(delId).toString())); try {
deleted++; for(int i = 0; i < ITERATIONS; i++) {
} int rand = random.nextInt(101);
if (rand < 5) {
index.optimize();
} else if (rand < 60) {
Document doc = getDocument();
index.addDocument(doc);
idStack.push(doc.get("id"));
added++;
} else {
// we just delete the last document added and remove it
// from the id stack so that it won't be removed twice:
String delId = null;
try {
delId = (String)idStack.pop();
} catch (EmptyStackException e) {
continue;
} }
if (maxWait > 0) { Term delTerm = new Term("id", new Integer(delId).toString());
try { int delCount = index.delete(delTerm);
rand = random.nextInt(maxWait); if (delCount != 1) {
//System.out.println("waiting " + rand + "ms"); throw new RuntimeException("Internal error: " + threadNumber + " deleted " + delCount +
Thread.sleep(rand); " documents, term=" + delTerm);
} catch (InterruptedException e) { }
e.printStackTrace(); deleted++;
} }
if (maxWait > 0) {
try {
rand = random.nextInt(maxWait);
//System.out.println("waiting " + rand + "ms");
Thread.sleep(rand);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} }
} }
} catch (IOException e) {
throw new RuntimeException(e);
} }
} } catch (IOException e) {
throw new RuntimeException(e);
private Document getDocument() {
Document doc = new Document();
doc.add(new Field("id", new Integer(id++).toString(), Field.Store.YES,
Field.Index.UN_TOKENIZED));
// add random stuff:
doc.add(new Field("content", new Integer(random.nextInt(1000)).toString(), Field.Store.YES,
Field.Index.TOKENIZED));
doc.add(new Field("content", new Integer(random.nextInt(1000)).toString(), Field.Store.YES,
Field.Index.TOKENIZED));
doc.add(new Field("all", "x", Field.Store.YES, Field.Index.TOKENIZED));
return doc;
} }
} }
private Document getDocument() {
Document doc = new Document();
synchronized (getClass()) {
doc.add(new Field("id", new Integer(id).toString(), Field.Store.YES,
Field.Index.UN_TOKENIZED));
id++;
}
// add random stuff:
doc.add(new Field("content", new Integer(random.nextInt(1000)).toString(), Field.Store.YES,
Field.Index.TOKENIZED));
doc.add(new Field("content", new Integer(random.nextInt(1000)).toString(), Field.Store.YES,
Field.Index.TOKENIZED));
doc.add(new Field("all", "x", Field.Store.YES, Field.Index.TOKENIZED));
return doc;
}
} }