/* * 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 org.apache.lucene.util.*; import org.apache.lucene.store.*; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.*; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.search.*; public class TestStressIndexing extends LuceneTestCase { private static abstract class TimedThread extends Thread { volatile boolean failed; int count; private static int RUN_TIME_MSEC = atLeast(1000); private TimedThread[] allThreads; abstract public void doWork() throws Throwable; TimedThread(TimedThread[] threads) { this.allThreads = threads; } @Override public void run() { final long stopTime = System.currentTimeMillis() + RUN_TIME_MSEC; count = 0; try { do { if (anyErrors()) break; doWork(); count++; } while(System.currentTimeMillis() < stopTime); } catch (Throwable e) { System.out.println(Thread.currentThread() + ": exc"); e.printStackTrace(System.out); failed = true; } } private boolean anyErrors() { for(int i=0;i<allThreads.length;i++) if (allThreads[i] != null && allThreads[i].failed) return true; return false; } } private class IndexerThread extends TimedThread { IndexWriter writer; int nextID; public IndexerThread(IndexWriter writer, TimedThread[] threads) { super(threads); this.writer = writer; } @Override public void doWork() throws Exception { // Add 10 docs: for(int j=0; j<10; j++) { Document d = new Document(); int n = random().nextInt(); d.add(newStringField("id", Integer.toString(nextID++), Field.Store.YES)); d.add(newTextField("contents", English.intToEnglish(n), Field.Store.NO)); writer.addDocument(d); } // Delete 5 docs: int deleteID = nextID-1; for(int j=0; j<5; j++) { writer.deleteDocuments(new Term("id", ""+deleteID)); deleteID -= 2; } } } private static class SearcherThread extends TimedThread { private Directory directory; public SearcherThread(Directory directory, TimedThread[] threads) { super(threads); this.directory = directory; } @Override public void doWork() throws Throwable { for (int i=0; i<100; i++) { IndexReader ir = DirectoryReader.open(directory); IndexSearcher is = newSearcher(ir); ir.close(); } count += 100; } } /* Run one indexer and 2 searchers against single index as stress test. */ public void runStressTest(Directory directory, MergeScheduler mergeScheduler) throws Exception { IndexWriter modifier = new IndexWriter(directory, newIndexWriterConfig(new MockAnalyzer(random())) .setOpenMode(OpenMode.CREATE) .setMaxBufferedDocs(10) .setMergeScheduler(mergeScheduler)); modifier.commit(); TimedThread[] threads = new TimedThread[4]; int numThread = 0; // One modifier that writes 10 docs then removes 5, over // and over: IndexerThread indexerThread = new IndexerThread(modifier, threads); threads[numThread++] = indexerThread; indexerThread.start(); IndexerThread indexerThread2 = new IndexerThread(modifier, threads); threads[numThread++] = indexerThread2; indexerThread2.start(); // Two searchers that constantly just re-instantiate the // searcher: SearcherThread searcherThread1 = new SearcherThread(directory, threads); threads[numThread++] = searcherThread1; searcherThread1.start(); SearcherThread searcherThread2 = new SearcherThread(directory, threads); threads[numThread++] = searcherThread2; searcherThread2.start(); for(int i=0;i<numThread;i++) threads[i].join(); modifier.close(); for(int i=0;i<numThread;i++) assertTrue(! threads[i].failed); //System.out.println(" Writer: " + indexerThread.count + " iterations"); //System.out.println("Searcher 1: " + searcherThread1.count + " searchers created"); //System.out.println("Searcher 2: " + searcherThread2.count + " searchers created"); } /* Run above stress test against RAMDirectory and then FSDirectory. */ public void testStressIndexAndSearching() throws Exception { Directory directory = newMaybeVirusCheckingDirectory(); if (directory instanceof MockDirectoryWrapper) { ((MockDirectoryWrapper) directory).setAssertNoUnrefencedFilesOnClose(true); } runStressTest(directory, new ConcurrentMergeScheduler()); directory.close(); } }