/* * ************************************************************************************* * 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.multithread; import com.espertech.esper.client.*; import com.espertech.esper.client.deploy.Module; import com.espertech.esper.support.bean.SupportBean; import com.espertech.esper.support.client.SupportConfigFactory; import com.espertech.esper.support.util.SupportMTUpdateListener; import junit.framework.TestCase; import java.io.File; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.*; /** * Test for multithread-safety of context. */ public class TestMTContext extends TestCase { private EPServiceProvider engine; public void setUp() { Configuration configuration = SupportConfigFactory.getConfiguration(); configuration.getEngineDefaults().getEventMeta().setDefaultEventRepresentation(Configuration.EventRepresentation.MAP); // use Map-type events for testing engine = EPServiceProviderManager.getDefaultProvider(configuration); engine.initialize(); } protected void tearDown() throws Exception { } public void testContextCountSimple() throws Exception { engine.getEPAdministrator().getConfiguration().addEventType(SupportBean.class); engine.getEPAdministrator().createEPL("create context HashByUserCtx as coalesce by consistent_hash_crc32(theString) from SupportBean granularity 10000000"); engine.getEPAdministrator().createEPL("@Name('select') context HashByUserCtx select theString from SupportBean"); trySendContextCountSimple(4, 5); } public void testContextUnique() throws Exception { String epl = "create schema ScoreCycle (userId string, keyword string, productId string, score long);\n" + "\n" + "create schema UserKeywordTotalStream (userId string, keyword string, sumScore long);\n" + "\n" + "create context HashByUserCtx as\n" + "coalesce by consistent_hash_crc32(userId) from ScoreCycle,\n" + "consistent_hash_crc32(userId) from UserKeywordTotalStream \n" + "granularity 10000000;\n" + "\n" + "context HashByUserCtx create window ScoreCycleWindow.std:unique(userId, keyword, productId) as ScoreCycle;\n" + "\n" + "context HashByUserCtx insert into ScoreCycleWindow select * from ScoreCycle;\n" + "\n" + "@Name('Select') context HashByUserCtx insert into UserKeywordTotalStream\n" + "select userId, keyword, sum(score) as sumScore from ScoreCycleWindow group by userId, keyword;"; engine.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); MyUpdateListener listener = new MyUpdateListener(); engine.getEPAdministrator().getStatement("Select").addListener(listener); List<Map> sendsT1 = new ArrayList<Map>(); sendsT1.add(makeEvent("A", "house", "P0", 1)); sendsT1.add(makeEvent("B", "house", "P0", 2)); List<Map> sendsT2 = new ArrayList<Map>(); sendsT2.add(makeEvent("B", "house", "P0", 3)); sendsT1.add(makeEvent("A", "house", "P0", 4)); ExecutorService threadPool = Executors.newFixedThreadPool(2); threadPool.submit(new SendEventRunnable(engine, sendsT1, "ScoreCycle")); threadPool.submit(new SendEventRunnable(engine, sendsT2, "ScoreCycle")); threadPool.shutdown(); threadPool.awaitTermination(1, TimeUnit.SECONDS); // compare List<Object> received = listener.getReceived(); for (Object item : received) { System.out.println(item); } assertEquals(4, received.size()); } private void trySendContextCountSimple(int numThreads, int numRepeats) throws Exception { SupportMTUpdateListener listener = new SupportMTUpdateListener(); engine.getEPAdministrator().getStatement("select").addListener(listener); List<Object> events = new ArrayList<Object>(); for (int i = 0; i < numRepeats; i++) { events.add(new SupportBean("E" + i, i)); } ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); Future future[] = new Future[numThreads]; for (int i = 0; i < numThreads; i++) { Callable callable = new SendEventCallable(i, engine, events.iterator()); future[i] = threadPool.submit(callable); } threadPool.shutdown(); threadPool.awaitTermination(10, TimeUnit.SECONDS); EventBean[] result = listener.getNewDataListFlattened(); assertEquals(numRepeats * numThreads, result.length); } private Map<String, Object> makeEvent(String userId, String keyword, String productId, long score) { Map<String, Object> theEvent = new LinkedHashMap<String, Object>(); theEvent.put("userId", userId); theEvent.put("keyword", keyword); theEvent.put("productId", productId); theEvent.put("score", score); return theEvent; } public static class MyUpdateListener implements UpdateListener { private List<Object> received = new ArrayList<Object>(); public synchronized void update(EventBean[] newEvents, EventBean[] oldEvents) { for (int i = 0; i < newEvents.length; i++) { received.add(newEvents[i].getUnderlying()); } } public List<Object> getReceived() { return received; } } public static class SendEventRunnable implements Runnable { private final EPServiceProvider engine; private final List<Map> events; private final String type; public SendEventRunnable(EPServiceProvider engine, List<Map> events, String type) { this.engine = engine; this.events = events; this.type = type; } public void run() { for (Map theEvent : events) { engine.getEPRuntime().sendEvent(theEvent, type); } } } }