001: package org.apache.lucene.index;
002:
003: /**
004: * Copyright 2004 The Apache Software Foundation
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import org.apache.lucene.util.*;
020: import org.apache.lucene.store.*;
021: import org.apache.lucene.document.*;
022: import org.apache.lucene.analysis.*;
023: import org.apache.lucene.index.*;
024: import org.apache.lucene.search.*;
025: import org.apache.lucene.queryParser.*;
026:
027: import org.apache.lucene.util.LuceneTestCase;
028:
029: import java.util.Random;
030: import java.io.File;
031:
032: public class TestStressIndexing extends LuceneTestCase {
033: private static final Analyzer ANALYZER = new SimpleAnalyzer();
034: private static final Random RANDOM = new Random();
035:
036: private static abstract class TimedThread extends Thread {
037: boolean failed;
038: int count;
039: private static int RUN_TIME_SEC = 6;
040: private TimedThread[] allThreads;
041:
042: abstract public void doWork() throws Throwable;
043:
044: TimedThread(TimedThread[] threads) {
045: this .allThreads = threads;
046: }
047:
048: public void run() {
049: final long stopTime = System.currentTimeMillis() + 1000
050: * RUN_TIME_SEC;
051:
052: count = 0;
053:
054: try {
055: while (System.currentTimeMillis() < stopTime
056: && !anyErrors()) {
057: doWork();
058: count++;
059: }
060: } catch (Throwable e) {
061: e.printStackTrace(System.out);
062: failed = true;
063: }
064: }
065:
066: private boolean anyErrors() {
067: for (int i = 0; i < allThreads.length; i++)
068: if (allThreads[i] != null && allThreads[i].failed)
069: return true;
070: return false;
071: }
072: }
073:
074: private static class IndexerThread extends TimedThread {
075: IndexWriter writer;
076: public int count;
077: int nextID;
078:
079: public IndexerThread(IndexWriter writer, TimedThread[] threads) {
080: super (threads);
081: this .writer = writer;
082: }
083:
084: public void doWork() throws Exception {
085: // Add 10 docs:
086: for (int j = 0; j < 10; j++) {
087: Document d = new Document();
088: int n = RANDOM.nextInt();
089: d.add(new Field("id", Integer.toString(nextID++),
090: Field.Store.YES, Field.Index.UN_TOKENIZED));
091: d.add(new Field("contents", English.intToEnglish(n),
092: Field.Store.NO, Field.Index.TOKENIZED));
093: writer.addDocument(d);
094: }
095:
096: // Delete 5 docs:
097: int deleteID = nextID - 1;
098: for (int j = 0; j < 5; j++) {
099: writer.deleteDocuments(new Term("id", "" + deleteID));
100: deleteID -= 2;
101: }
102: }
103: }
104:
105: private static class SearcherThread extends TimedThread {
106: private Directory directory;
107:
108: public SearcherThread(Directory directory, TimedThread[] threads) {
109: super (threads);
110: this .directory = directory;
111: }
112:
113: public void doWork() throws Throwable {
114: for (int i = 0; i < 100; i++)
115: (new IndexSearcher(directory)).close();
116: count += 100;
117: }
118: }
119:
120: /*
121: Run one indexer and 2 searchers against single index as
122: stress test.
123: */
124: public void runStressTest(Directory directory, boolean autoCommit,
125: MergeScheduler mergeScheduler) throws Exception {
126: IndexWriter modifier = new IndexWriter(directory, autoCommit,
127: ANALYZER, true);
128:
129: modifier.setMaxBufferedDocs(10);
130:
131: TimedThread[] threads = new TimedThread[4];
132:
133: if (mergeScheduler != null)
134: modifier.setMergeScheduler(mergeScheduler);
135:
136: // One modifier that writes 10 docs then removes 5, over
137: // and over:
138: IndexerThread indexerThread = new IndexerThread(modifier,
139: threads);
140: threads[0] = indexerThread;
141: indexerThread.start();
142:
143: IndexerThread indexerThread2 = new IndexerThread(modifier,
144: threads);
145: threads[2] = indexerThread2;
146: indexerThread2.start();
147:
148: // Two searchers that constantly just re-instantiate the
149: // searcher:
150: SearcherThread searcherThread1 = new SearcherThread(directory,
151: threads);
152: threads[3] = searcherThread1;
153: searcherThread1.start();
154:
155: SearcherThread searcherThread2 = new SearcherThread(directory,
156: threads);
157: threads[3] = searcherThread2;
158: searcherThread2.start();
159:
160: indexerThread.join();
161: indexerThread2.join();
162: searcherThread1.join();
163: searcherThread2.join();
164:
165: modifier.close();
166:
167: assertTrue("hit unexpected exception in indexer",
168: !indexerThread.failed);
169: assertTrue("hit unexpected exception in indexer2",
170: !indexerThread2.failed);
171: assertTrue("hit unexpected exception in search1",
172: !searcherThread1.failed);
173: assertTrue("hit unexpected exception in search2",
174: !searcherThread2.failed);
175:
176: //System.out.println(" Writer: " + indexerThread.count + " iterations");
177: //System.out.println("Searcher 1: " + searcherThread1.count + " searchers created");
178: //System.out.println("Searcher 2: " + searcherThread2.count + " searchers created");
179: }
180:
181: /*
182: Run above stress test against RAMDirectory and then
183: FSDirectory.
184: */
185: public void testStressIndexAndSearching() throws Exception {
186:
187: // RAMDir
188: Directory directory = new MockRAMDirectory();
189: runStressTest(directory, true, null);
190: directory.close();
191:
192: // FSDir
193: String tempDir = System.getProperty("java.io.tmpdir");
194: File dirPath = new File(tempDir, "lucene.test.stress");
195: directory = FSDirectory.getDirectory(dirPath);
196: runStressTest(directory, true, null);
197: directory.close();
198:
199: // With ConcurrentMergeScheduler, in RAMDir
200: directory = new MockRAMDirectory();
201: runStressTest(directory, true, new ConcurrentMergeScheduler());
202: directory.close();
203:
204: // With ConcurrentMergeScheduler, in FSDir
205: directory = FSDirectory.getDirectory(dirPath);
206: runStressTest(directory, true, new ConcurrentMergeScheduler());
207: directory.close();
208:
209: // With ConcurrentMergeScheduler and autoCommit=false, in RAMDir
210: directory = new MockRAMDirectory();
211: runStressTest(directory, false, new ConcurrentMergeScheduler());
212: directory.close();
213:
214: // With ConcurrentMergeScheduler and autoCommit=false, in FSDir
215: directory = FSDirectory.getDirectory(dirPath);
216: runStressTest(directory, false, new ConcurrentMergeScheduler());
217: directory.close();
218:
219: _TestUtil.rmDir(dirPath);
220: }
221: }
|