/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* 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.regression.nwtable;
import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.scopetest.SupportUpdateListener;
import com.espertech.esper.supportregression.bean.SupportBean;
import com.espertech.esper.supportregression.client.SupportConfigFactory;
import com.espertech.esper.util.CollectionUtil;
import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class TestTableMTGroupedAccessReadIntoTableWriteAggColConsistency extends TestCase
{
private static final Logger log = LoggerFactory.getLogger(TestTableMTGroupedAccessReadIntoTableWriteAggColConsistency.class);
private EPServiceProvider epService;
public void setUp()
{
Configuration config = SupportConfigFactory.getConfiguration();
config.addEventType(Local10ColEvent.class);
config.addEventType(SupportBean.class);
epService = EPServiceProviderManager.getDefaultProvider(config);
epService.initialize();
}
/**
* Table:
* create table vartotal (key string primary key, tc0 sum(int), tc1 sum(int) ... tc9 sum(int))
*
* Seed the table with a number of groups, no new ones are added or deleted during the test.
* For a given number of seconds and a given number of groups:
* - Single writer updates a group (round-robin), each group associates with 10 columns .
* - N readers pull a group's columns, round-robin, check that all 10 values are consistent.
* - The 10 values are sum-int totals that are expected to all have the same value.
*/
public void testMT() throws Exception
{
tryMT(10, 3);
}
private void tryMT(int numGroups, int numSeconds) throws Exception
{
String eplCreateVariable = "create table vartotal (key string primary key, " + CollectionUtil.toString(getDeclareCols()) + ")";
epService.getEPAdministrator().createEPL(eplCreateVariable);
String eplInto = "into table vartotal select " + CollectionUtil.toString(getIntoCols()) + " from Local10ColEvent group by groupKey";
epService.getEPAdministrator().createEPL(eplInto);
// initialize groups
String[] groups = new String[numGroups];
for (int i = 0; i < numGroups; i++) {
groups[i] = "G" + i;
epService.getEPRuntime().sendEvent(new Local10ColEvent(groups[i], 0));
}
WriteRunnable writeRunnable = new WriteRunnable(epService, groups);
ReadRunnable readRunnable = new ReadRunnable(epService, groups);
// start
Thread t1 = new Thread(writeRunnable);
Thread t2 = new Thread(readRunnable);
t1.start();
t2.start();
// wait
Thread.sleep(numSeconds * 1000);
// shutdown
writeRunnable.setShutdown(true);
readRunnable.setShutdown(true);
// join
log.info("Waiting for completion");
t1.join();
t2.join();
assertNull(writeRunnable.getException());
assertNull(readRunnable.getException());
assertTrue(writeRunnable.numEvents > 100);
assertTrue(readRunnable.numQueries > 100);
System.out.println("Send " + writeRunnable.numEvents + " and performed " + readRunnable.numQueries + " reads");
}
private Collection<String> getDeclareCols() {
List<String> cols = new ArrayList<String>();
for (int i = 0; i < 10; i++) { // 10 columns, not configurable
cols.add("tc" + i + " sum(int)");
}
return cols;
}
private Collection<String> getIntoCols() {
List<String> cols = new ArrayList<String>();
for (int i = 0; i < 10; i++) { // 10 columns, not configurable
cols.add("sum(c" + i + ") as tc" + i);
}
return cols;
}
public static class WriteRunnable implements Runnable {
private final EPServiceProvider epService;
private final String[] groups;
private RuntimeException exception;
private boolean shutdown;
private int numEvents;
public WriteRunnable(EPServiceProvider epService, String[] groups) {
this.epService = epService;
this.groups = groups;
}
public void setShutdown(boolean shutdown) {
this.shutdown = shutdown;
}
public void run() {
log.info("Started event send for write");
try {
while(!shutdown) {
int groupNum = numEvents % groups.length;
epService.getEPRuntime().sendEvent(new Local10ColEvent(groups[groupNum], numEvents));
numEvents++;
}
}
catch (RuntimeException ex) {
log.error("Exception encountered: " + ex.getMessage(), ex);
exception = ex;
}
log.info("Completed event send for write");
}
public RuntimeException getException() {
return exception;
}
}
public static class ReadRunnable implements Runnable {
private final EPServiceProvider epService;
private final String[] groups;
private RuntimeException exception;
private boolean shutdown;
private int numQueries;
public ReadRunnable(EPServiceProvider epService, String[] groups) {
this.epService = epService;
this.groups = groups;
}
public void setShutdown(boolean shutdown) {
this.shutdown = shutdown;
}
public void run() {
log.info("Started event send for read");
try {
String eplSelect = "select vartotal[theString] as out from SupportBean";
SupportUpdateListener listener = new SupportUpdateListener();
epService.getEPAdministrator().createEPL(eplSelect).addListener(listener);
while(!shutdown) {
int groupNum = numQueries % groups.length;
epService.getEPRuntime().sendEvent(new SupportBean(groups[groupNum], 0));
EventBean event = listener.assertOneGetNewAndReset();
assertEvent((Map)event.get("out"));
numQueries++;
}
}
catch (RuntimeException ex) {
log.error("Exception encountered: " + ex.getMessage(), ex);
exception = ex;
}
log.info("Completed event send for read");
}
private void assertEvent(Map info) {
Object tc0 = info.get("tc0");
for (int i = 1; i < 10; i++) {
assertEquals(tc0, info.get("tc" + i));
}
}
public RuntimeException getException() {
return exception;
}
}
public static final class Local10ColEvent {
private final String groupKey;
private final int c0;
private final int c1;
private final int c2;
private final int c3;
private final int c4;
private final int c5;
private final int c6;
private final int c7;
private final int c8;
private final int c9;
public Local10ColEvent(String groupKey, int value) {
this.groupKey = groupKey;
this.c0 = value;
this.c1 = value;
this.c2 = value;
this.c3 = value;
this.c4 = value;
this.c5 = value;
this.c6 = value;
this.c7 = value;
this.c8 = value;
this.c9 = value;
}
public String getGroupKey() {
return groupKey;
}
public int getC0() {
return c0;
}
public int getC1() {
return c1;
}
public int getC2() {
return c2;
}
public int getC3() {
return c3;
}
public int getC4() {
return c4;
}
public int getC5() {
return c5;
}
public int getC6() {
return c6;
}
public int getC7() {
return c7;
}
public int getC8() {
return c8;
}
public int getC9() {
return c9;
}
}
}