/* * ************************************************************************************* * 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.dispatchmodel; import junit.framework.TestCase; import com.espertech.esper.dispatch.DispatchService; import com.espertech.esper.dispatch.DispatchServiceImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.List; import java.util.Arrays; import java.util.concurrent.*; /** * A model for testing multithreaded dispatches to listeners. * <p> * Each thread in a loop: * Next producer invoke * Producer generates next integer * Producer sends int[] {num, 0} */ public class TestMTDispatch extends TestCase { private static final Log log = LogFactory.getLog(TestMTDispatch.class); public void testSceneOne() throws Exception { DispatchService dispatchService = new DispatchServiceImpl(); DispatchListenerImpl listener = new DispatchListenerImpl(); //UpdateDispatchViewModel updateDispatchView = new UpdateDispatchViewNonConcurrentModel(dispatchService, listener); UpdateDispatchViewOrderEnforcingModel updateDispatchView = new UpdateDispatchViewOrderEnforcingModel(dispatchService, listener); int numThreads = 2; int numActions = 10000; int ratioDoubleAdd = 5; // generates {(1,0),(2,0), (3,0)} trySend(numThreads, numActions, ratioDoubleAdd, updateDispatchView, dispatchService); // assert size List<int[][]> result = listener.getReceived(); assertEquals(numActions * numThreads, result.size()); // analyze result int[] nominals = new int[result.size()]; for (int i = 0; i < result.size(); i++) { int[][] entry = result.get(i); //System.out.println("entry=" + print(entry)); nominals[i] = entry[0][0]; assertEquals("Order not correct: #" + i, (i + 1), nominals[i]); // Assert last digits and nominals, i.e. (1, 0) (1, 1), (1, 2) for (int j = 0; j < entry.length; j++) { assertEquals(nominals[i], entry[j][0]); assertEquals(j, entry[j][1]); } } } private void trySend(int numThreads, int numCount, int ratioDoubleAdd, UpdateDispatchViewModel updateDispatchView, DispatchService dispatchService) throws Exception { // execute ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); Future future[] = new Future[numThreads]; DispatchCallable callables[] = new DispatchCallable[numThreads]; DispatchProducer producer = new DispatchProducer(updateDispatchView); for (int i = 0; i < numThreads; i++) { callables[i] = new DispatchCallable(producer, i, numCount, ratioDoubleAdd, updateDispatchView, dispatchService); future[i] = threadPool.submit(callables[i]); } threadPool.shutdown(); threadPool.awaitTermination(10, TimeUnit.SECONDS); for (int i = 0; i < numThreads; i++) { assertTrue((Boolean) future[i].get()); } } private String print(int[][] input) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < input.length; i++) { buf.append(Arrays.toString(input[i])); buf.append(","); } return buf.toString(); } public static class DispatchCallable implements Callable { private static final Log log = LogFactory.getLog(DispatchCallable.class); private DispatchProducer sharedProducer; private final int threadNum; private final int numActions; private final int ratioDoubleAdd; private final UpdateDispatchViewModel updateDispatchView; private final DispatchService dispatchService; public DispatchCallable(DispatchProducer sharedProducer, int threadNum, int numActions, int ratioDoubleAdd, UpdateDispatchViewModel updateDispatchView, DispatchService dispatchService) { this.sharedProducer = sharedProducer; this.threadNum = threadNum; this.numActions = numActions; this.ratioDoubleAdd = ratioDoubleAdd; this.updateDispatchView = updateDispatchView; this.dispatchService = dispatchService; } public Object call() throws Exception { log.info(".call Thread " + Thread.currentThread().getId() + " starting"); for (int i = 0; i < numActions; i++) { if (i % 10000 == 1) { log.info(".call Thread " + Thread.currentThread().getId() + " at " + i); } int nominal = sharedProducer.next(); if (i % ratioDoubleAdd == 1) { updateDispatchView.add(new int[] {nominal, 1}); } dispatchService.dispatch(); } log.info(".call Thread " + Thread.currentThread().getId() + " done"); return true; } } }