diff --git a/querydsl-lucene/pom.xml b/querydsl-lucene/pom.xml index 3aef9e442..5f1563713 100644 --- a/querydsl-lucene/pom.xml +++ b/querydsl-lucene/pom.xml @@ -49,14 +49,21 @@ ${project.parent.version} test test-jar + + + + org.springframework + spring-aop + 3.0.3.RELEASE + test + + + + org.apache.commons + commons-io + 1.3.2 + test - - - org.springframework - spring-aop - 3.0.3.RELEASE - test - diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/WriteLockObtainFailedException.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/WriteLockObtainFailedException.java new file mode 100644 index 000000000..938d1af17 --- /dev/null +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/WriteLockObtainFailedException.java @@ -0,0 +1,21 @@ +package com.mysema.query.lucene.session; + +import com.mysema.query.QueryException; + +public class WriteLockObtainFailedException extends QueryException { + + private static final long serialVersionUID = 4569418223905066659L; + + public WriteLockObtainFailedException(String msg) { + super(msg); + } + + public WriteLockObtainFailedException(String msg, Throwable t) { + super(msg, t); + } + + public WriteLockObtainFailedException(Throwable t) { + super(t); + } + +} diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneWriterImpl.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java similarity index 70% rename from querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneWriterImpl.java rename to querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java index 99d0a301b..b4283e3b3 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneWriterImpl.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java @@ -11,23 +11,29 @@ import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.index.Term; import org.apache.lucene.store.Directory; +import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.util.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mysema.query.QueryException; import com.mysema.query.lucene.session.LuceneWriter; +import com.mysema.query.lucene.session.WriteLockObtainFailedException; -public class LuceneWriterImpl implements LuceneWriter { +public class FileLockingWriter implements LuceneWriter { - private static final Logger logger = LoggerFactory.getLogger(LuceneWriterImpl.class); + protected static final Logger logger = LoggerFactory.getLogger(LuceneWriter.class); - private IndexWriter writer; + protected IndexWriter writer; @Nullable - private final ReleaseListener releaseListener; + protected final ReleaseListener releaseListener; + + private volatile boolean leased = false; - public LuceneWriterImpl(Directory directory, boolean createNew, ReleaseListener releaseListener) { + public FileLockingWriter(Directory directory, boolean createNew, long defaultLockTimeout, + ReleaseListener releaseListener) { + IndexWriter.setDefaultWriteLockTimeout(defaultLockTimeout); try { if (createNew == false) { try { @@ -47,10 +53,16 @@ public class LuceneWriterImpl implements LuceneWriter { MaxFieldLength.LIMITED); } + } catch (LockObtainFailedException e) { + logger.error("Got timeout " + System.currentTimeMillis()); + throw new WriteLockObtainFailedException(e); } catch (IOException e) { throw new QueryException(e); } this.releaseListener = releaseListener; + if(logger.isDebugEnabled()) { + logger.debug("Created writer " + writer); + } } @Override @@ -90,6 +102,9 @@ public class LuceneWriterImpl implements LuceneWriter { // TODO What would be best way to control this? writer.optimize(); writer.close(); + if(logger.isDebugEnabled()) { + logger.debug("Closed writer " + writer); + } } catch (IOException e) { logger.error("Writer close failed", e); try { @@ -107,5 +122,19 @@ public class LuceneWriterImpl implements LuceneWriter { public IndexWriter getIndexWriter() { return writer; } + + public void lease() { + leased = true; + } + + public void release() { + leased = false; + } + + public boolean isLeased() { + return leased; + } + + } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java index 0574c39b7..aa554f921 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java @@ -2,7 +2,9 @@ package com.mysema.query.lucene.session.impl; import java.io.File; import java.io.IOException; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; @@ -22,11 +24,18 @@ public class LuceneSessionFactoryImpl implements LuceneSessionFactory { private final Directory directory; - private final AtomicReference searcher = new AtomicReference(); - + @Nullable + private volatile LuceneSearcher searcher; + + ExecutorService searchUpdater = Executors.newSingleThreadExecutor(); + + private final AtomicBoolean creatingNew = new AtomicBoolean(false); + @Nullable private final ReleaseListener releaseListener; + private long defaultLockTimeout = 2000; + public LuceneSessionFactoryImpl(String indexPath) throws IOException { File folder = new File(indexPath); if (!folder.exists() && !folder.mkdirs()) { @@ -60,8 +69,8 @@ public class LuceneSessionFactoryImpl implements LuceneSessionFactory { if (!LuceneSessionHolder.hasCurrentSession(this)) { - if (logger.isDebugEnabled()) { - logger.debug("Binding new session to thread"); + if (logger.isTraceEnabled()) { + logger.trace("Binding new session to thread"); } LuceneSession session = openSession(LuceneSessionHolder.getReadOnly()); @@ -76,56 +85,58 @@ public class LuceneSessionFactoryImpl implements LuceneSessionFactory { return new LuceneSessionImpl(this, readOnly); } - public LuceneWriterImpl getWriter(boolean createNew) { - return new LuceneWriterImpl(directory, createNew, releaseListener); + public FileLockingWriter getWriter(boolean createNew) { + return new FileLockingWriter(directory, createNew, defaultLockTimeout, releaseListener); } public LuceneSearcher leaseSearcher() { try { - if (searcher.get() == null) { - createNewSearcher(null); + if (searcher == null) { + synchronized (this) { + if (searcher == null) { + if (logger.isDebugEnabled()) { + logger.debug("Creating first searcher"); + } + searcher = createNewSearcher(); + } + } } - - // Checking do we need to refresh the reader - LuceneSearcher s = searcher.get(); - if (!s.isCurrent()) { - // Underlying index has changed - - // Decreasing the reference counter so that - // count can go to zero either here or - // when final searcher has done it's job - // This pairs with createNewSearcher incRef() - try { - s.release(); - } catch (QueryException e) { - logger.error("Could not release index reader", e); + if (creatingNew.compareAndSet(false, true)) { + if (!searcher.isCurrent()) { + try { + // This release pairs with createNewSearcher lease + searcher.release(); + } catch (QueryException e) { + logger.error("Could not release searcher", e); + } + searcher = createNewSearcher(); } - createNewSearcher(s); + creatingNew.set(false); } // Incrementing reference as we lease this out - // This pairs with closeReaders decRef() - searcher.get().lease(); - - return searcher.get(); + // This pairs with LuceneSessions close + searcher.lease(); + return searcher; } catch (IOException e) { throw new QueryException(e); } } - private LuceneSearcher createNewSearcher(@Nullable LuceneSearcher expected) throws IOException { + private LuceneSearcher createNewSearcher() throws IOException { LuceneSearcher s = new LuceneSearcher(directory, releaseListener); - if (!searcher.compareAndSet(expected, s)) { - // Some thread already created a new one so just close this - s.release(); - } else { - // Incrementing the reference count first time - // We want to keep using the same reader until the index is changed - s.lease(); + if (logger.isDebugEnabled()) { + logger.debug("Created searcher " + s); } - return searcher.get(); + // Increment the first time + s.lease(); + return s; + } + + public void setDefaultLockTimeout(long defaultLockTimeout) { + this.defaultLockTimeout = defaultLockTimeout; } } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionHolder.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionHolder.java index 63585de96..3c21b12aa 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionHolder.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionHolder.java @@ -64,6 +64,7 @@ public final class LuceneSessionHolder { private static Map getSessions() { if (sessions.get() == null) { sessions.set(new HashMap()); + } return sessions.get(); } @@ -74,8 +75,10 @@ public final class LuceneSessionHolder { try { for (LuceneSession session : getSessions().values()) { try { + //System.out.println("session holder close"); session.close(); } catch (QueryException e) { + //System.out.println("failed to close session " + e.getCause().getMessage()); logger.error("Failed to close session", e); } } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java index f93c67fec..d17ef0e39 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java @@ -22,7 +22,7 @@ public class LuceneSessionImpl implements LuceneSession { private LuceneSearcher searcher; @Nullable - private LuceneWriterImpl writer; + private FileLockingWriter writer; private final LuceneSerializer serializer = new LuceneSerializer(true, true); @@ -83,7 +83,15 @@ public class LuceneSessionImpl implements LuceneSession { } if (writer != null) { - writer.close(); + if (writer.isLeased()) { + try { + writer.commit(); + } finally { + writer.release(); + } + } else { + writer.close(); + } } if (searcherException != null) { diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneTransactionHandler.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneTransactionHandler.java index f15d592f7..be69321b3 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneTransactionHandler.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneTransactionHandler.java @@ -17,14 +17,17 @@ public class LuceneTransactionHandler { public Object transactionalMethod(ProceedingJoinPoint joinPoint, LuceneTransactional annotation) throws Throwable { - if(logger.isDebugEnabled()) { - logger.debug("Starting LuceneTransactional method"); + if (logger.isTraceEnabled()) { + logger.trace("LuceneSessionHolder.lease"); } - + LuceneSessionHolder.lease(annotation.readOnly()); try { return joinPoint.proceed(); } finally { + if (logger.isTraceEnabled()) { + logger.trace("LuceneSessionHolder.release"); + } LuceneSessionHolder.release(); } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ReleaseListener.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ReleaseListener.java index 1e4079c3d..6514c5f99 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ReleaseListener.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ReleaseListener.java @@ -1,5 +1,7 @@ package com.mysema.query.lucene.session.impl; +import com.mysema.query.lucene.session.LuceneWriter; + /** * Helps to make sure the resources are released as they should be. * @@ -11,6 +13,6 @@ public interface ReleaseListener { void release(LuceneSearcher searcher); - void close(LuceneWriterImpl writer); + void close(LuceneWriter writer); } diff --git a/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/LuceneSessionFactoryTest.java b/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/LuceneSessionFactoryTest.java index 4e8dc2c25..c0ff3358f 100644 --- a/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/LuceneSessionFactoryTest.java +++ b/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/LuceneSessionFactoryTest.java @@ -21,7 +21,6 @@ import org.junit.Test; import com.mysema.query.lucene.LuceneQuery; import com.mysema.query.lucene.session.impl.LuceneSearcher; import com.mysema.query.lucene.session.impl.LuceneSessionFactoryImpl; -import com.mysema.query.lucene.session.impl.LuceneWriterImpl; import com.mysema.query.lucene.session.impl.ReleaseListener; import com.mysema.query.types.path.NumberPath; import com.mysema.query.types.path.StringPath; @@ -98,7 +97,7 @@ public class LuceneSessionFactoryTest { session.close(); } - @Test(expected=SessionNotBoundException.class) + @Test(expected = SessionNotBoundException.class) public void CurrentSession() { sessionFactory.getCurrentSession(); } @@ -146,10 +145,14 @@ public class LuceneSessionFactoryTest { private class ReleaseCounter implements ReleaseListener { List searchers = new ArrayList(); - List writers = new ArrayList(); + + List writers = new ArrayList(); + Map leases = new HashMap(); + Map releases = new HashMap(); - Map closes = new HashMap(); + + Map closes = new HashMap(); public void lease(LuceneSearcher searcher) { if (!searchers.contains(searcher)) { @@ -168,7 +171,7 @@ public class LuceneSessionFactoryTest { releases.put(searcher, releases.get(searcher) + 1); } - public void close(LuceneWriterImpl writer) { + public void close(LuceneWriter writer) { if (!writers.contains(writer)) { writers.add(writer); } @@ -178,7 +181,7 @@ public class LuceneSessionFactoryTest { closes.put(writer, closes.get(writer) + 1); } } - + @Test public void Reset() { addData(sessionFactory); @@ -186,15 +189,15 @@ public class LuceneSessionFactoryTest { LuceneSession session = sessionFactory.openSession(true); assertEquals(4, session.createQuery().count()); session.close(); - + session = sessionFactory.openSession(false); - + assertEquals(4, session.createQuery().count()); session.beginReset().addDocument(getDocument()); session.flush(); assertEquals(1, session.createQuery().count()); session.close(); - + session = sessionFactory.openSession(true); assertEquals(1, session.createQuery().count()); session.close(); @@ -204,50 +207,50 @@ public class LuceneSessionFactoryTest { public void ResourcesAreReleased() throws IOException { ReleaseCounter counter = new ReleaseCounter(); - + sessionFactory = new LuceneSessionFactoryImpl(directory, counter); - + LuceneSession session = sessionFactory.openSession(false); session.beginAppend().addDocument(getDocument()); session.flush(); - + LuceneQuery query = session.createQuery(); assertEquals(1, query.where(year.gt(1800)).count()); session.beginAppend().addDocument(getDocument()); session.flush(); - + query = session.createQuery(); assertEquals(2, query.where(year.gt(1800)).count()); - + session.close(); - - //Second session + + // Second session session = sessionFactory.openSession(true); query = session.createQuery(); assertEquals(2, query.where(year.gt(1800)).count()); session.close(); - + assertEquals(3, counter.leases.size()); assertEquals(3, counter.releases.size()); assertEquals(3, counter.searchers.size()); assertEquals(1, counter.closes.size()); assertEquals(1, counter.writers.size()); - - //First and second searchers should be released totally - assertEquals(2, (int)counter.leases.get(counter.searchers.get(0))); - assertEquals(2, (int)counter.releases.get(counter.searchers.get(0))); - assertEquals(2, (int)counter.leases.get(counter.searchers.get(1))); - assertEquals(2, (int)counter.releases.get(counter.searchers.get(1))); + // First and second searchers should be released totally + assertEquals(2, (int) counter.leases.get(counter.searchers.get(0))); + assertEquals(2, (int) counter.releases.get(counter.searchers.get(0))); - //Third searcher leaves it as current - assertEquals(2, (int)counter.leases.get(counter.searchers.get(2))); - assertEquals(1, (int)counter.releases.get(counter.searchers.get(2))); - - //The writer should be closed - assertEquals(1, (int)counter.closes.get(counter.writers.get(0))); + assertEquals(2, (int) counter.leases.get(counter.searchers.get(1))); + assertEquals(2, (int) counter.releases.get(counter.searchers.get(1))); + + // Third searcher leaves it as current + assertEquals(2, (int) counter.leases.get(counter.searchers.get(2))); + assertEquals(1, (int) counter.releases.get(counter.searchers.get(2))); + + // The writer should be closed + assertEquals(1, (int) counter.closes.get(counter.writers.get(0))); } } diff --git a/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/ThreadingTest.java b/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/ThreadingTest.java new file mode 100644 index 000000000..1d1c28bb0 --- /dev/null +++ b/querydsl-lucene/src/test/java/com/mysema/query/lucene/session/ThreadingTest.java @@ -0,0 +1,312 @@ +package com.mysema.query.lucene.session; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; + +import com.mysema.query.lucene.session.impl.LuceneSessionFactoryImpl; +import com.mysema.query.lucene.session.impl.LuceneTransactionHandler; + +public class ThreadingTest { + + private LuceneSessionFactoryImpl sessionFactory; + + private TestDao dao; + + private static class Task implements Callable { + + TestDao dao; + + String action; + + Task(TestDao dao, String action) { + this.dao = dao; + this.action = action; + } + + @Override + public Throwable call() throws Exception { + try { + if (action.equals("read")) { + dao.read(); + } + if (action.equals("write")) { + dao.write(); + } + if (action.equals("reset")) { + dao.reset(); + } + return null; + } catch (Throwable t) { + return t; + } + } + + } + + private static interface TestDao { + void write(); + + void reset(); + + void read(); + } + + private static class TestDaoImpl implements TestDao { + + private LuceneSessionFactory sessionFactory; + + private QDocument doc = new QDocument("d"); + + int counter = 1; + + int readCount = 0; + + private final Object writeLock = new Object(); + + private final Object readLock = new Object(); + + private final Object resetLock = new Object(); + + TestDaoImpl(LuceneSessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @Override + @LuceneTransactional + public void write() { + LuceneSession session = sessionFactory.getCurrentSession(); + + LuceneWriter writer = session.beginAppend(); + int numOfDocs = 1000; + for (int i = 0; i < numOfDocs; i++) { + writer.addDocument(QueryTestHelper.createDocument( + "title " + counter, + "", + "", + counter, + 0)); + + } + synchronized (writeLock) { + counter += numOfDocs; + } + System.out.println("Added " + numOfDocs + " documents "); + } + + @Override + @LuceneTransactional + public void reset() { + LuceneSession session = sessionFactory.getCurrentSession(); + + synchronized (resetLock) { + counter = 0; + } + session.beginReset().addDocument( + QueryTestHelper.createDocument("title " + counter, "", "", counter, 0)); + System.out.println("Resetted index "); + } + + @Override + @LuceneTransactional(readOnly = true) + public void read() { + LuceneSession session = sessionFactory.getCurrentSession(); + int count = (int) session.createQuery().where(doc.title.startsWith("title")).count(); + + synchronized (readLock) { + readCount++; + if (readCount % 1000 == 0) { + System.out.println("Document count is " + count + " after " + readCount + + " reads"); + } + } + } + + } + + @Before + public void before() throws IOException { + String path = "target/index"; + FileUtils.deleteDirectory(new File(path)); + + sessionFactory = new LuceneSessionFactoryImpl("target/index"); + // Initialize index + QueryTestHelper.addData(sessionFactory); + + AspectJProxyFactory factory = new AspectJProxyFactory(new TestDaoImpl(sessionFactory)); + factory.addAspect(new LuceneTransactionHandler()); + dao = factory.getProxy(); + } + + private static class TaskRunner implements Callable> { + + private String action; + + private int requestsPerMinute; + + private int starDelayInSecs; + + public boolean stop = false; + + private int clients; + + ScheduledExecutorService threads; + + TestDao dao; + + TaskRunner(String action, int clients, int requestsPerMinute, int startDelayInSecs, + TestDao dao) { + this.action = action; + this.clients = clients; + this.requestsPerMinute = requestsPerMinute; + this.starDelayInSecs = startDelayInSecs; + this.dao = dao; + } + + @Override + public List call() throws Exception { + + threads = Executors.newScheduledThreadPool(clients); + + List errors = new ArrayList(); + + List> tasks = new ArrayList>(); + + // Fire tasks + for (int i = 0; i < clients; i++) { + tasks.add(threads.schedule( + new Task(dao, action), + i * starDelayInSecs, + TimeUnit.SECONDS)); + } + + long startTime = System.currentTimeMillis(); + int numOfRequests = 0; + // Take results and fire again + while (tasks.size() > 0) { + int taskReadyIndex = -1; + for (int i = 0; i < tasks.size(); i++) { + try { + tasks.get(i).get(1, TimeUnit.MILLISECONDS); + taskReadyIndex = i; + break; + } catch (TimeoutException e) { + // Ignore + } + } + if (taskReadyIndex == -1) { + continue; + } + + Throwable error = tasks.get(taskReadyIndex).get(); + tasks.remove(taskReadyIndex); + numOfRequests++; + if (error != null) { + errors.add(error); + } + + if (!stop) { + tasks.add(threads.schedule( + new Task(dao, action), + 60 / requestsPerMinute, + TimeUnit.SECONDS)); + } + } + float elapsedMins = ((float) (System.currentTimeMillis() - startTime) / 1000) / 60; + System.out.println(numOfRequests + " " + action + " requests, " + numOfRequests + / elapsedMins + " requests/min"); + threads.shutdown(); + return errors; + } + } + + @Test + @Ignore + public void Simultaneous() throws InterruptedException, ExecutionException { + + sessionFactory.setDefaultLockTimeout(5000); + + ExecutorService threads = Executors.newFixedThreadPool(3); + + int simulationtimeInSecs = 60; + + // Readers + TaskRunner readRunner = new TaskRunner("read", 100, 120, simulationtimeInSecs / 1000, dao); + Future> reads = threads.submit(readRunner); + + // Writers + TaskRunner writeRunner = new TaskRunner("write", 1, 6, 0, dao); + Future> writes = threads.submit(writeRunner); + + // Resetters + TaskRunner resetRunner = new TaskRunner("reset", 1, 2, 15, dao); + Future> resets = threads.submit(resetRunner); + + Thread.sleep(simulationtimeInSecs * 1000); + + readRunner.stop = true; + writeRunner.stop = true; + resetRunner.stop = true; + + List readErrors = reads.get(); + List writeErrors = writes.get(); + List resetErrors = resets.get(); + threads.shutdown(); + + System.out.println("Read errors: " + readErrors.size()); + System.out.println("Write errors: " + writeErrors.size()); + System.out.println("Reset errors: " + resetErrors.size()); + + printErrors(readErrors); + printErrors(writeErrors); + printErrors(resetErrors); + + assertEquals("Read errors", 0, readErrors.size()); + assertEquals("Write errors", 0, writeErrors.size()); + assertEquals("Reset errors", 0, resetErrors.size()); + + // + // Map, Integer> errorTypes = new HashMap, Integer>(); + // List errors = new ArrayList(); + // for (int i = 0; i < runs; i++) { + // Throwable t = pool.take().get(); + // if (t != null) { + // if (!errorTypes.containsKey(t.getClass())) { + // errorTypes.put(t.getClass(), 0); + // } + // errorTypes.put(t.getClass(), errorTypes.get(t.getClass()) + 1); + // errors.add(t); + // } + // } + } + + private void printErrors(List errors) { + int count = 0; + for (Throwable t : errors) { + System.out.println("------------------"); + System.out.println(""); + t.printStackTrace(System.out); + if (count++ > 3) { + break; + } + } + + } +} diff --git a/querydsl-lucene/src/test/resources/log4j.properties.example b/querydsl-lucene/src/test/resources/log4j.properties.example new file mode 100644 index 000000000..2f9467c28 --- /dev/null +++ b/querydsl-lucene/src/test/resources/log4j.properties.example @@ -0,0 +1,9 @@ +# Configure an appender that logs to console +log4j.rootLogger=info, A1 +log4j.threshold=debug +log4j.appender.A1=org.apache.log4j.ConsoleAppender +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c{1} - %m%n + +# Configuration of logging levels for different packages +log4j.logger.com.mysema.query.lucene=DEBUG