package org.infinispan.lucene.profiling; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Field.Store; import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.infinispan.Cache; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.lucene.directory.DirectoryBuilder; import org.infinispan.lucene.testutils.LuceneSettings; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.test.AbstractCacheTest; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.TransportFlags; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.jgroups.protocols.DISCARD; import org.testng.annotations.Test; /** * @author Sanne Grinovero <sanne@infinispan.org> (C) 2011 Red Hat Inc. */ @SuppressWarnings("deprecation") @Test(groups = "profiling", testName = "lucene.profiling.DynamicTopologyStressTest", sequential = true) public class DynamicTopologyStressTest extends MultipleCacheManagersTest { private static final Log log = LogFactory.getLog(DynamicTopologyStressTest.class); private static final boolean KEEP_GOING = false; private static final boolean VISUAL_PROGRESS_FEEDBACK = false; /** Number of seconds the test will run. Should run for some minutes **/ private static final int SECONDS_TOTAL = 15; /** How many Documents to write in each second **/ private static final int WRITES_PER_SECOND = 100; /** Number of Terms written in the index **/ private static final int INITIAL_INDEX_TERMS = 2000; private static final String INDEX_NAME = "unstableIndex"; private static final String FIELDNAME = "fieldname"; /** Number of reading nodes **/ private static final int READERS = 5; private final AtomicBoolean failed = new AtomicBoolean(false); private volatile int lastWrittenTermId = 0; /** Registry of clustered CacheManagers used as readers **/ private EmbeddedCacheManager[] readers = new EmbeddedCacheManager[READERS]; private DISCARD[] discardPerNode = new DISCARD[READERS]; private EmbeddedCacheManager writingNode; @Override protected void createCacheManagers() throws Throwable { ConfigurationBuilder cb = AbstractCacheTest.getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, false); cb.invocationBatching().disable(); TransportFlags transportFlags = new TransportFlags().withMerge(true); writingNode = addClusterEnabledCacheManager(cb, transportFlags); for (int i = 0; i < READERS; i++) { readers[i] = addClusterEnabledCacheManager(cb, transportFlags); Cache<Object, Object> cache = readers[i].getCache(); discardPerNode[i] = TestingUtil.getDiscardForCache(cache); TestingUtil.setDelayForCache(cache, 1, 1); TestingUtil.blockUntilViewReceived(cache, i + 1); } } @Test void testDirectoryUnstableCluster() throws IOException { Directory masterDirectory = DirectoryBuilder.newDirectoryInstance(writingNode.getCache(), writingNode.getCache(), writingNode.getCache(), INDEX_NAME).create(); SharedState sharedIndexState = IndexReadingStressTest.fillDirectory(masterDirectory, INITIAL_INDEX_TERMS); ExecutorService executor = Executors.newFixedThreadPool(READERS + 1); try { executor.execute(new ConstantWritingThread(masterDirectory, sharedIndexState)); for (int i=0; i<READERS; i++) { executor.execute(new ConstantReadingThread(masterDirectory, sharedIndexState)); } executor.shutdown(); executor.awaitTermination(SECONDS_TOTAL * 2, TimeUnit.SECONDS); //wait for all jobs to finish } catch (InterruptedException e) { log.error(e); assert false : "unexpected interruption"; } assert failed.get() == false; } private void failed(Exception e) { log.error(e); if (! KEEP_GOING) { failed.set(true); } } public class ConstantWritingThread implements Runnable { private final Directory masterDirectory; public ConstantWritingThread(Directory masterDirectory, SharedState sharedIndexState) { this.masterDirectory = masterDirectory; } @Override public void run() { while (lastWrittenTermId < (SECONDS_TOTAL * WRITES_PER_SECOND) && failed.get() == false) { IndexWriter writer = null; try { int toWrite = lastWrittenTermId + 1; writer = LuceneSettings.openWriter(masterDirectory, 3); // 3 or any low setting Document doc = new Document(); Field field = new StringField(FIELDNAME, "HA" + toWrite, Store.YES); doc.add(field); writer.addDocument(doc); writer.commit(); lastWrittenTermId = toWrite; if (VISUAL_PROGRESS_FEEDBACK) System.out.println("Written: " + doc); Thread.sleep(1000 / WRITES_PER_SECOND); } catch (IOException e) { failed(e); return; } catch (InterruptedException e) { failed(e); return; } finally { try { if (writer != null) { writer.close(); } } catch (IOException e) { failed(e); return; } } } } } public class ConstantReadingThread implements Runnable { private final Directory masterDirectory; public ConstantReadingThread(Directory masterDirectory, SharedState sharedIndexState) { this.masterDirectory = masterDirectory; } @Override public void run() { while (lastWrittenTermId < (SECONDS_TOTAL * WRITES_PER_SECOND) && failed.get() == false) { IndexReader indexReader = null; try { int i = lastWrittenTermId; indexReader = DirectoryReader.open(masterDirectory); IndexSearcher indexSearcher = new IndexSearcher(indexReader); if (i==0) continue; // nothing written yet String termValue = "HA" + i; Query query = new TermQuery(new Term( FIELDNAME, termValue)); TopDocs docs = indexSearcher.search(query, 1); if (docs.totalHits != 1) { failed.set(true); log.error("String '" + termValue + "' should exist but was not found in index"); } if (VISUAL_PROGRESS_FEEDBACK) System.out.print("."); Thread.sleep(1); } catch (IOException e) { failed(e); return; } catch (InterruptedException e) { failed(e); return; } finally { try { if (indexReader != null) { indexReader.close(); } } catch (IOException e) { failed(e); return; } } } } } }