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: import org.apache.lucene.util._TestUtil;
027:
028: import org.apache.lucene.util.LuceneTestCase;
029:
030: import java.util.Random;
031: import java.io.File;
032:
033: public class TestAtomicUpdate extends LuceneTestCase {
034: private static final Analyzer ANALYZER = new SimpleAnalyzer();
035: private static final Random RANDOM = new Random();
036:
037: private static abstract class TimedThread extends Thread {
038: boolean failed;
039: int count;
040: private static int RUN_TIME_SEC = 3;
041: private TimedThread[] allThreads;
042:
043: abstract public void doWork() throws Throwable;
044:
045: TimedThread(TimedThread[] threads) {
046: this .allThreads = threads;
047: }
048:
049: public void run() {
050: final long stopTime = System.currentTimeMillis() + 1000
051: * RUN_TIME_SEC;
052:
053: count = 0;
054:
055: try {
056: while (System.currentTimeMillis() < stopTime
057: && !anyErrors()) {
058: doWork();
059: count++;
060: }
061: } catch (Throwable e) {
062: e.printStackTrace(System.out);
063: failed = true;
064: }
065: }
066:
067: private boolean anyErrors() {
068: for (int i = 0; i < allThreads.length; i++)
069: if (allThreads[i] != null && allThreads[i].failed)
070: return true;
071: return false;
072: }
073: }
074:
075: private static class IndexerThread extends TimedThread {
076: IndexWriter writer;
077: public int count;
078:
079: public IndexerThread(IndexWriter writer, TimedThread[] threads) {
080: super (threads);
081: this .writer = writer;
082: }
083:
084: public void doWork() throws Exception {
085: // Update all 100 docs...
086: for (int i = 0; i < 100; i++) {
087: Document d = new Document();
088: int n = RANDOM.nextInt();
089: d.add(new Field("id", Integer.toString(i),
090: Field.Store.YES, Field.Index.UN_TOKENIZED));
091: d
092: .add(new Field("contents", English
093: .intToEnglish(i + 10 * count),
094: Field.Store.NO, Field.Index.TOKENIZED));
095: writer.updateDocument(new Term("id", Integer
096: .toString(i)), d);
097: }
098: }
099: }
100:
101: private static class SearcherThread extends TimedThread {
102: private Directory directory;
103:
104: public SearcherThread(Directory directory, TimedThread[] threads) {
105: super (threads);
106: this .directory = directory;
107: }
108:
109: public void doWork() throws Throwable {
110: IndexReader r = IndexReader.open(directory);
111: try {
112: assertEquals(100, r.numDocs());
113: } catch (Throwable t) {
114: throw t;
115: }
116: r.close();
117: }
118: }
119:
120: /*
121: Run one indexer and 2 searchers against single index as
122: stress test.
123: */
124: public void runTest(Directory directory) throws Exception {
125:
126: TimedThread[] threads = new TimedThread[4];
127:
128: IndexWriter writer = new IndexWriter(directory, ANALYZER, true);
129:
130: // Establish a base index of 100 docs:
131: for (int i = 0; i < 100; i++) {
132: Document d = new Document();
133: d.add(new Field("id", Integer.toString(i), Field.Store.YES,
134: Field.Index.UN_TOKENIZED));
135: d.add(new Field("contents", English.intToEnglish(i),
136: Field.Store.NO, Field.Index.TOKENIZED));
137: writer.addDocument(d);
138: }
139: writer.flush();
140:
141: IndexerThread indexerThread = new IndexerThread(writer, threads);
142: threads[0] = indexerThread;
143: indexerThread.start();
144:
145: IndexerThread indexerThread2 = new IndexerThread(writer,
146: threads);
147: threads[1] = indexerThread2;
148: indexerThread2.start();
149:
150: SearcherThread searcherThread1 = new SearcherThread(directory,
151: threads);
152: threads[2] = 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: writer.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: //System.out.println(" Writer: " + indexerThread.count + " iterations");
176: //System.out.println("Searcher 1: " + searcherThread1.count + " searchers created");
177: //System.out.println("Searcher 2: " + searcherThread2.count + " searchers created");
178: }
179:
180: /*
181: Run above stress test against RAMDirectory and then
182: FSDirectory.
183: */
184: public void testAtomicUpdates() throws Exception {
185:
186: Directory directory;
187:
188: // First in a RAM directory:
189: directory = new MockRAMDirectory();
190: runTest(directory);
191: directory.close();
192:
193: // Second in an FSDirectory:
194: String tempDir = System.getProperty("java.io.tmpdir");
195: File dirPath = new File(tempDir, "lucene.test.atomic");
196: directory = FSDirectory.getDirectory(dirPath);
197: runTest(directory);
198: directory.close();
199: _TestUtil.rmDir(dirPath);
200: }
201: }
|