/* * ************************************************************************************* * 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.epl.variable; import junit.framework.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Random; import java.util.concurrent.Callable; public class VariableServiceCallable implements Callable { private static final Log log = LogFactory.getLog(VariableServiceCallable.class); private final Random random; private final String[] variables; private final VariableReader[] readers; private final VariableService variableService; private final VariableVersionCoord variableVersionCoord; private final int numLoops; private final int[][] results; private final int[] marks; public VariableServiceCallable(String[] variables, VariableService variableService, VariableVersionCoord variableVersionCoord, int numLoops) { this.random = new Random(); this.variables = variables; this.variableService = variableService; this.variableVersionCoord = variableVersionCoord; this.numLoops = numLoops; results = new int[numLoops][variables.length]; marks = new int[numLoops]; readers = new VariableReader[variables.length]; for (int i = 0; i < variables.length; i++) { readers[i] = variableService.getReader(variables[i]); } } public Object call() { // For each loop for (int i = 0; i < numLoops; i++) { doLoop(i); } return true; // assertions therefore return a result that fails the test } private void doLoop(int loopNumber) { // Set a mark, there should be no number above that number int mark = variableVersionCoord.setVersionGetMark(); int[] indexes = getIndexesShuffled(variables.length, random, loopNumber); marks[loopNumber] = mark; // Perform first read of all variables int[] readResults = new int[variables.length]; readAll(indexes, readResults, mark); // Start a write cycle for the write we are getting an exclusive write lock variableService.getReadWriteLock().writeLock().lock(); // Write every second of the variables for (int i = 0; i < indexes.length; i++) { int variableNum = indexes[i]; String variableName = variables[variableNum]; if (i % 2 == 0) { int newMark = variableVersionCoord.incMark(); if (log.isDebugEnabled()) { log.debug(".run Thread " + Thread.currentThread().getId() + " at mark " + mark + " write variable '" + variableName + "' new value " + newMark); } variableService.write(readers[variableNum].getVariableNumber(), newMark); } } // Commit (apply) the changes and unlock variableService.commit(); variableService.getReadWriteLock().writeLock().unlock(); // Read again and compare to first result results[loopNumber] = new int[variables.length]; readAll(indexes, results[loopNumber], mark); // compare first read with second read, written values are NOT visible for (int i = 0; i < variables.length; i++) { if (results[loopNumber][i] != readResults[i]) { String text = "Error in loop#" + loopNumber + " comparing a re-read result for variable " + variables[i] + " expected " + readResults[i] + " but was " + results[loopNumber][i]; Assert.fail(text); } } } private void readAll(int[] indexes, int[] results, int mark) { for (int j = 0; j < indexes.length; j++) { int index = indexes[j]; String variableName = variables[index]; Integer value = (Integer) readers[index].getValue(); results[index] = value; if (log.isDebugEnabled()) { log.debug(".run Thread " + Thread.currentThread().getId() + " at mark " + mark + " read variable '" + variableName + " value " + value); } } } public int[][] getResults() { return results; } public int[] getMarks() { return marks; } // Make a list between 0 and N for each variable private static int[] getIndexes(int length, Random random, int loopNum) { int[] indexRandomized = new int[length]; for (int i = 0; i < indexRandomized.length; i++) { indexRandomized[i] = i; } return indexRandomized; } // Make a list between 0 and N for each variable private static int[] getIndexesShifting(int length, Random random, int loopNum) { int[] indexRandomized = new int[length]; int start = loopNum % length; int count = 0; for (int i = start; i < indexRandomized.length; i++) { indexRandomized[count++] = i; } for (int i = 0; i < start; i++) { indexRandomized[count++] = i; } return indexRandomized; } // Make a random list between 0 and N for each variable private static int[] getIndexesShuffled(int length, Random random, int loopNum) { int[] indexRandomized = new int[length]; for (int i = 0; i < indexRandomized.length; i++) { indexRandomized[i] = i; } for (int i = 0; i < length; i++) { int indexOne = random.nextInt(length); int indexTwo = random.nextInt(length); int temp = indexRandomized[indexOne]; indexRandomized[indexOne] = indexRandomized[indexTwo]; indexRandomized[indexTwo] = temp; } return indexRandomized; } }