/*
* *************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
* *************************************************************************************
*/
package com.espertech.esper.filter;
import java.util.Vector;
import java.util.List;
import java.util.LinkedList;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
import junit.framework.TestCase;
import com.espertech.esper.support.bean.SupportBean;
import com.espertech.esper.support.filter.SupportFilterSpecBuilder;
import com.espertech.esper.support.filter.SupportFilterHandle;
import com.espertech.esper.support.filter.IndexTreeBuilderRunnable;
import com.espertech.esper.support.event.SupportEventTypeFactory;
import com.espertech.esper.support.event.SupportEventBeanFactory;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class TestIndexTreeBuilderMultithreaded extends TestCase
{
private Vector<FilterSpecCompiled> testFilterSpecs;
private Vector<EventBean> matchedEvents;
private Vector<EventBean> unmatchedEvents;
private EventType eventType;
private FilterHandleSetNode topNode;
private IndexTreeBuilder builder;
private List<FilterHandle> filterCallbacks;
private List<IndexTreePath> pathsAddedTo;
public void setUp()
{
builder = new IndexTreeBuilder();
eventType = SupportEventTypeFactory.createBeanType(SupportBean.class);
topNode = new FilterHandleSetNode();
filterCallbacks = new LinkedList<FilterHandle>();
pathsAddedTo = new LinkedList<IndexTreePath>();
testFilterSpecs = new Vector<FilterSpecCompiled>();
matchedEvents = new Vector<EventBean>();
unmatchedEvents = new Vector<EventBean>();
// Any int and double value specified here must match only the current filter spec not any other filter spec
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.GREATER_OR_EQUAL, 100000 }));
matchedEvents.add(makeEvent(9999999, -1));
unmatchedEvents.add(makeEvent(0, -1));
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.GREATER_OR_EQUAL, 10,
"doublePrimitive", FilterOperator.EQUAL, 0.5}));
matchedEvents.add(makeEvent(10, 0.5));
unmatchedEvents.add(makeEvent(0, 0.5));
testFilterSpecs.add(makeSpec(new Object[] { "doublePrimitive", FilterOperator.EQUAL, 0.8}));
matchedEvents.add(makeEvent(-1, 0.8));
unmatchedEvents.add(makeEvent(-1, 0.1));
testFilterSpecs.add(makeSpec(new Object[] { "doublePrimitive", FilterOperator.EQUAL, 99.99,
"intPrimitive", FilterOperator.LESS, 1}));
matchedEvents.add(makeEvent(0, 99.99));
unmatchedEvents.add(makeEvent(2, 0.5));
testFilterSpecs.add(makeSpec(new Object[] { "doublePrimitive", FilterOperator.GREATER, .99,
"intPrimitive", FilterOperator.EQUAL, 5001}));
matchedEvents.add(makeEvent(5001, 1.1));
unmatchedEvents.add(makeEvent(5002, 0.98));
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.LESS, -99000}));
matchedEvents.add(makeEvent(-99001, -1));
unmatchedEvents.add(makeEvent(-98999, -1));
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.GREATER_OR_EQUAL, 11,
"doublePrimitive", FilterOperator.GREATER, 888.0}));
matchedEvents.add(makeEvent(11, 888.001));
unmatchedEvents.add(makeEvent(10, 888));
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.EQUAL, 973,
"doublePrimitive", FilterOperator.EQUAL, 709.0}));
matchedEvents.add(makeEvent(973, 709));
unmatchedEvents.add(makeEvent(0, 0.5));
testFilterSpecs.add(makeSpec(new Object[] { "intPrimitive", FilterOperator.EQUAL, 973,
"doublePrimitive", FilterOperator.EQUAL, 655.0}));
matchedEvents.add(makeEvent(973, 655));
unmatchedEvents.add(makeEvent(33838, 655.5));
}
public void testVerifyFilterSpecSet()
{
// Add all the above filter definitions
for (FilterSpecCompiled filterSpec : testFilterSpecs)
{
FilterValueSet filterValues = filterSpec.getValueSet(null, null, null);
FilterHandle callback = new SupportFilterHandle();
filterCallbacks.add(callback);
pathsAddedTo.add(builder.add(filterValues, callback, topNode));
}
// None of the not-matching events should cause any match
for (EventBean theEvent : unmatchedEvents)
{
List<FilterHandle> matches = new LinkedList<FilterHandle>();
topNode.matchEvent(theEvent, matches);
assertTrue(matches.size() == 0);
}
// All of the matching events should cause exactly one match
for (EventBean theEvent : matchedEvents)
{
List<FilterHandle> matches = new LinkedList<FilterHandle>();
topNode.matchEvent(theEvent, matches);
assertTrue(matches.size() == 1);
}
// Remove all expressions previously added
int count = 0;
for (IndexTreePath treePath : pathsAddedTo)
{
FilterHandle callback = filterCallbacks.get(count++);
builder.remove(eventType, callback, treePath, topNode);
}
// After the remove no matches are expected
for (EventBean theEvent : matchedEvents)
{
List<FilterHandle> matches = new LinkedList<FilterHandle>();
topNode.matchEvent(theEvent, matches);
assertTrue(matches.size() == 0);
}
}
public void testMultithreaded() throws Exception
{
FilterHandleSetNode topNode = new FilterHandleSetNode();
performMultithreadedTest(topNode, 2, 1000, 1);
performMultithreadedTest(topNode, 3, 1000, 1);
performMultithreadedTest(topNode, 4, 1000, 1);
performMultithreadedTest(new FilterHandleSetNode(), 2, 1000, 1);
performMultithreadedTest(new FilterHandleSetNode(), 3, 1000, 1);
performMultithreadedTest(new FilterHandleSetNode(), 4, 1000, 1);
}
private void performMultithreadedTest(FilterHandleSetNode topNode,
int numberOfThreads,
int numberOfRunnables,
int numberOfSecondsSleep) throws Exception
{
log.info(".performMultithreadedTest Loading thread pool work queue,numberOfRunnables=" + numberOfRunnables);
ThreadPoolExecutor pool = new ThreadPoolExecutor(0, numberOfThreads, 99999, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < numberOfRunnables; i++)
{
IndexTreeBuilderRunnable runnable = new IndexTreeBuilderRunnable(eventType, topNode,
testFilterSpecs, matchedEvents, unmatchedEvents);
pool.execute(runnable);
}
log.info(".performMultithreadedTest Starting thread pool, threads=" + numberOfThreads);
pool.setCorePoolSize(numberOfThreads);
// Sleep X seconds
sleep(numberOfSecondsSleep);
log.info(".performMultithreadedTest Completed, numberOfRunnables=" + numberOfRunnables +
" numberOfThreads=" + numberOfThreads +
" completed=" + pool.getCompletedTaskCount());
pool.shutdown();
pool.awaitTermination(1, TimeUnit.SECONDS);
assertTrue(pool.getCompletedTaskCount() == numberOfRunnables);
}
private void sleep(int sec)
{
try
{
Thread.sleep(sec * 1000);
}
catch (InterruptedException e)
{
log.warn(e);
}
}
private FilterSpecCompiled makeSpec(Object[] args)
{
return SupportFilterSpecBuilder.build(eventType, args);
}
private EventBean makeEvent(int aInt, double aDouble)
{
SupportBean bean = new SupportBean();
bean.setIntPrimitive(aInt);
bean.setDoublePrimitive(aDouble);
return SupportEventBeanFactory.createObject(bean);
}
private static final Log log = LogFactory.getLog(TestIndexTreeBuilderMultithreaded.class);
}