Author: psteitz Date: Mon Jul 16 23:11:36 2007 New Revision: 556823 URL: http://svn.apache.org/viewvc?view=rev&rev=556823 Log: Initial Commit.
Added: jakarta/commons/sandbox/performance/ jakarta/commons/sandbox/performance/build.properties jakarta/commons/sandbox/performance/build.xml jakarta/commons/sandbox/performance/config.xml jakarta/commons/sandbox/performance/logging.properties jakarta/commons/sandbox/performance/src/ jakarta/commons/sandbox/performance/src/java/ jakarta/commons/sandbox/performance/src/java/org/ jakarta/commons/sandbox/performance/src/java/org/apache/ jakarta/commons/sandbox/performance/src/java/org/apache/commons/ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ClientThread.java jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ConfigurationException.java jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPClientThread.java jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPTest.java Added: jakarta/commons/sandbox/performance/build.properties URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/build.properties?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/build.properties (added) +++ jakarta/commons/sandbox/performance/build.properties Mon Jul 16 23:11:36 2007 @@ -0,0 +1,24 @@ +############################################################################### +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +# Remote maven repository +mavenRepo=http://repo1.maven.org/maven2 + +# JDBC driver +jdbc-jar=/home/phil/mysql/mysql-connector-java-5.0.2.jar + Added: jakarta/commons/sandbox/performance/build.xml URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/build.xml?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/build.xml (added) +++ jakarta/commons/sandbox/performance/build.xml Mon Jul 16 23:11:36 2007 @@ -0,0 +1,124 @@ +<!-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + --> + +<project name="DBCPTest" default="run" basedir="."> + + <property name="src" location="src"/> + <property name="build" location="build"/> + <property name="lib" location="lib"/> + + <property name="component-propfile" value="${basedir}/build.properties"/> + <property file="${component-propfile}"/> + + <path id="compile.classpath"> + <pathelement location="${jdbc-jar}"/> + <fileset dir="${lib}"> + <include name="*.jar"/> + </fileset> + </path> + + <path id="run.classpath"> + <pathelement path="${build}"/> + <pathelement path="${java.class.path}"/> + <path refid="compile.classpath" /> + </path> + + <target name="init"> + <mkdir dir="${build}"/> + <mkdir dir="${lib}"/> + </target> + + <target name="get-collections"> + <get + src="${mavenRepo}/commons-collections/commons-collections/3.1/commons-collections-3.1.jar" + dest="${lib}/commons-collections-3.1.jar" + usetimestamp="true"/> + </target> + + <target name="get-beanutils"> + <get + src="${mavenRepo}/commons-beanutils/commons-beanutils/1.6.1/commons-beanutils-1.6.1.jar" + dest="${lib}/commons-beanutils-1.6.1.jar" + usetimestamp="true"/> + </target> + + <target name="get-digester"> + <get + src="${mavenRepo}/commons-digester/commons-digester/1.4.1/commons-digester-1.4.1.jar" + dest="${lib}/commons-digester-1.4.1.jar" + usetimestamp="true"/> + </target> + + <target name="get-math"> + <get + src="${mavenRepo}/commons-math/commons-math/1.1/commons-math-1.1.jar" + dest="${lib}/commons-math-1.1.jar" + usetimestamp="true"/> + </target> + + <target name="get-dbcp"> + <get + src="${mavenRepo}/commons-dbcp/commons-dbcp/1.2.2/commons-dbcp-1.2.2.jar" + dest="${lib}/commons-dbcp-1.2.2.jar" + usetimestamp="true"/> + </target> + + <target name="get-pool"> + <get + src="${mavenRepo}/commons-pool/commons-pool/1.3/commons-pool-1.3.jar" + dest="${lib}/commons-pool-1.3.jar" + usetimestamp="true"/> + </target> + + <target name="get-logging"> + <get + src="${mavenRepo}/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar" + dest="${lib}/commons-logging-1.0.4.jar" + usetimestamp="true"/> + </target> + + <target name="get-deps" + depends="get-collections,get-beanutils,get-digester,get-math,get-logging,get-dbcp,get-pool"> + </target> + + <target name="compile" depends="clean,init,get-deps"> + <javac srcdir="${src}/java" + destdir="${build}"> + <classpath refid="compile.classpath"/> + <compilerarg value="-Xlint:unchecked" /> + </javac> + <copy file="${basedir}/config.xml" tofile="${build}/config.xml"/> + <copy file="${basedir}/logging.properties" tofile="${build}/logging.properties"/> + </target> + + <target name="run" depends="compile"> + <java classname="org.apache.commons.performance.dbcp.DBCPTest" fork="true"> + <classpath refid="run.classpath"/> + <jvmarg + value="-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger"/> + <jvmarg value="-Djava.util.logging.config.file=logging.properties"/> + </java> + </target> + + <target name="clean"> + <delete dir="${build}"/> + </target> +</project> Added: jakarta/commons/sandbox/performance/config.xml URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/config.xml?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/config.xml (added) +++ jakarta/commons/sandbox/performance/config.xml Mon Jul 16 23:11:36 2007 @@ -0,0 +1,86 @@ +<!-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + --> + +<configuration> + <database> + <driver>com.mysql.jdbc.Driver</driver> + <url>jdbc:mysql:///test</url> + <username></username> + <password></password> + </database> + + <connection-factory> + <!-- DriverManager or Driver --> + <type>DriverManager</type> + <auto-commit>true</auto-commit> + <read-only>false</read-only> + <!-- Validation query to use when testOnBorrow or testOnReturn is true --> + <validation-query></validation-query> + </connection-factory> + + <poolable-connection-factory> + <!-- PoolableConnectionFactory or CPDSConnectionFactory (not yet) --> + <type>PoolableConnectionFactory</type> + <pool-prepared-statements>true</pool-prepared-statements> + <max-open-statements>-1</max-open-statements> + </poolable-connection-factory> + + <pool> + <!-- GenericObjectPool or AbandonedObjectPool --> + <type>GenericObjectPool</type> + <max-active>15</max-active> + <max-idle>15</max-idle> + <min-idle>0</min-idle> + <max-wait>-1</max-wait> + <!-- block, fail, or grow --> + <exhausted-action>block</exhausted-action> + <test-on-borrow>false</test-on-borrow> + <test-on-return>false</test-on-return> + <time-between-evictions>-1</time-between-evictions> + <tests-per-eviction>3</tests-per-eviction> + <idle-timeout>-1</idle-timeout> + <test-while-idle>false</test-while-idle> + </pool> + + <!-- Ignored unless pool type is AbandonedObjectPool --> + <abandoned-config> + <log-abandoned>true</log-abandoned> + <remove-abandoned>true</remove-abandoned> + <abandoned-timeout>50000</abandoned-timeout> + </abandoned-config> + + <run> + <!-- integerIndexed, integerScan, or textScan --> + <query-type>integerIndexed</query-type> + <iterations>1000</iterations> + <clients>50</clients> + <delay-mean>250</delay-mean> + <delay-sigma>50</delay-sigma> + <!-- constant, gaussian, or poisson --> + <delay-type>gaussian</delay-type> + <!-- none, linear, random --> + <ramp-type>random</ramp-type> + <period>20000</period> + <!-- none, oscillating (others?)--> + <cycle-type>oscillating</cycle-type> + </run> + +</configuration> Added: jakarta/commons/sandbox/performance/logging.properties URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/logging.properties?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/logging.properties (added) +++ jakarta/commons/sandbox/performance/logging.properties Mon Jul 16 23:11:36 2007 @@ -0,0 +1,38 @@ +############################################################################### +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +.level=WARNING + +org.apache.commons.pool.level=FINE +org.apache.commons.dbcp.level=FINE +org.apache.commons.performance.level=FINE + +java.util.logging.ConsoleHandler.level=SEVERE +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.FileHandler.level=FINE +java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter + +java.util.logging.FileHandler.pattern=%h/dbcpTest/dbcpSoak%u.log + +java.util.logging.FileHandler.limit=1000000 + +java.util.logging.FileHandler.count=10 + + Added: jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ClientThread.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ClientThread.java?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ClientThread.java (added) +++ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/ClientThread.java Mon Jul 16 23:11:36 2007 @@ -0,0 +1,286 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.performance; + +import java.util.List; +import java.util.logging.Logger; + +import org.apache.commons.math.random.RandomData; +import org.apache.commons.math.random.RandomDataImpl; +import org.apache.commons.math.stat.descriptive.SummaryStatistics; +import org.apache.commons.math.stat.descriptive.SummaryStatisticsImpl; + +/** + * Base for performance / load test clients. + * Run method executes init, then setup-execute-cleanup in a loop, gathering + * performance statistics, with time between executions determined by nextDelay + * method. See [EMAIL PROTECTED] for details on interarrival time computation. + * + */ +public abstract class ClientThread implements Runnable { + + /** Number of iterations */ + protected long iterations; + /** Mean time between requests */ + protected long delay; + /** Standard deviation of delay distribution */ + protected double sigma; + /** Delay type - determines how next start times are computed */ + protected String delayType; + /** Period for cyclic mean delay */ + protected long period; + /** Cycle type */ + protected String cycleType; + /** Ramp type */ + protected String rampType; + /** Logger shared by client threads */ + protected Logger logger = null; + /** List of statistics to which to append stats for this client */ + protected List <SummaryStatistics> statsList = null; + /** Start time of run */ + protected long startTime; + /** Start time of current period */ + protected long periodStart; + /** Last mean delay */ + protected double lastMean; + /** Random data generator */ + protected RandomData randomData; + /** Whether or now this thread is ramping up */ + protected boolean rampingUp = true; + + /** + * Create a client thread. + * + * @param iterations number of iterations + * @param delay mean time between client requests + * @param delayType distribution of time between client requests + * @param period period of cycle for cyclic load + * @param cycleType type of cycle for mean delay + * @param logger common logger shared by all clients + * @param statsList List of SummaryStatistics to add results to + */ + public ClientThread(long iterations, long delay, double sigma, + String delayType, long period, String cycleType, + String rampType, Logger logger, + List <SummaryStatistics> statsList) { + this.iterations = iterations; + this.delay = delay; + this.sigma = sigma; + this.delayType = delayType; + this.period = period; + this.cycleType = cycleType; + this.rampType = rampType; + this.logger = logger; + this.statsList = statsList; + } + + public void run() { + try { + init(); + } catch (Exception ex) { + logger.severe("init failed."); + ex.printStackTrace(); + return; + } + long start = 0; + startTime = System.currentTimeMillis(); + long lastStart = startTime; + long numMisses = 0; + long numErrors = 0; + SummaryStatistics stats = new SummaryStatisticsImpl(); + randomData = new RandomDataImpl(); + periodStart = System.currentTimeMillis(); + lastMean = (double) (2 * delay); // Ramp up, if any, starts here + for (int i = 0; i < iterations; i++) { + try { + setup(); + // Generate next interarrival time. If that is in the + // past, go right away and log a miss; otherwise wait. + long elapsed = System.currentTimeMillis() - lastStart; + long nextDelay = nextDelay(); + if (elapsed > nextDelay) { + numMisses++; + } else { + try { + Thread.sleep(nextDelay - elapsed); + } catch (InterruptedException ex) { + logger.info("Sleep interrupted"); + } + } + + // Fire the request and measure response time + start = System.currentTimeMillis(); + execute(); + } catch (Exception ex) { + ex.printStackTrace(); + numErrors++; + } finally { + try { + stats.addValue(System.currentTimeMillis() - start); + lastStart = start; + cleanUp(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // Report statistics + logger.info(stats.toString() + + "Number of misses: " + numMisses + "\n" + + "Number or errors: " + numErrors + "\n"); + statsList.add(stats); + } + + /** Executed once at the beginning of the run */ + protected void init() throws Exception {} + + /** Executed at the beginning of each iteration */ + protected void setup() throws Exception {} + + /** Executed in finally block of iteration try-catch */ + protected void cleanUp() throws Exception {} + + /** Core iteration code. Timings are based on this, + * so keep it tight. + * */ + public abstract void execute() throws Exception; + + /** + * <p>Computes the next interarrival time (time to wait between requests) + * based on configured values for mean delay, delay type, cycle type, + * ramp type and period. + * </p> + * <p>Currently supports constant (just returning mean delay time), Poisson + * and Gaussian distributed random time delays, linear and random ramps, + * and oscillating / non-oscillating cycle types. + * </p> + * <p>If delayType = "constant" the configured delay mean is always returned. + * If delayType is "gaussian" or "exponential" and cycleType is "none", + * random deviates with the configured parameters are returned. + * </p> + * <p>If delayType is not "constant" and cycleType is "oscillating", means + * of random deviates ramp up and down between delay and twice delay. Ramp + * type is controlled by rampType. Linear rampType means the means + * increase or decrease linearly over the time of the period. Random + * makes random jumps up or down toward the next peak or trough. "None" for + * rampType under oscillating cycleType makes the means alternate bttween + * peak (delay) and trough (twice delay) with no ramp between. + * </p> + * <p>For non-oscillating, non-constant runs, linear and random rampTypes + * work similarly, but over just one ramp up period at the beginning of + * the run. + * </p> + * + * @param currentTime current time + * @return next value for delay + */ + protected long nextDelay() { + long currentTime = System.currentTimeMillis(); + double mean = 0; + if (delayType.equals("constant")) { + //TODO: should support single ramp up to constant + return delay; + } else { // delay not constant, use random variate + + // Determine mean to use + double doubleDelay = (double) delay; + double top = 2d * doubleDelay; // delay is peak, ramp starts at top + if (cycleType.equals("none")) { + if (rampType.equals("none") || + (currentTime - startTime) > period) { + // use configured mean + mean = doubleDelay; + } else if (rampType.equals("linear")) { // single period linear + double prop = (double) (currentTime - startTime) / period ; + mean = top - doubleDelay * prop; + } else { // Random jumps down to delay - single period + // Where we last were as proportion of way down to delay + double lastProp = + (top - lastMean) / doubleDelay; + // Make a random jump toward 1 (1 = all the way down) + double prop = randomData.nextUniform(lastProp, 1); + mean = top - doubleDelay * prop; + } + } else if (cycleType.equals("oscillating")) { + // First check if we need to change directions + if ((currentTime - periodStart) >= period) { + if (rampingUp) { + rampingUp = false; + lastMean = doubleDelay; + } else { + rampingUp = true; + lastMean = top; + } + periodStart = currentTime; + } + if (rampType.equals("none")) { // mean or twice mean, no ramp + if (rampingUp) { + mean = top; + } else { + mean = doubleDelay; + } + } else if (rampType.equals("linear")) { // ramp down, then up + double prop = + (double)(currentTime - periodStart) / (double) period; + if (rampingUp) { + mean = top - doubleDelay * prop; + } else { + mean = doubleDelay + doubleDelay * prop; + } + } else { // random jumps down, then back up + // Where we last were as proportion of way down to delay + double lastProp = + (top - lastMean) / doubleDelay; + // Where we would be if this were a linear ramp + double linearProp = + (double)(currentTime - periodStart) / (double) period; + // Need to govern size of jumps, otherwise "convergence" + // can be too fast - use linear ramp as governor + if ((rampingUp && (lastProp > linearProp)) || + (!rampingUp && (lastProp < linearProp))) { // Slow down + lastProp = linearProp; + } + double prop = 0; + if (rampingUp) { // Random jump toward 1 + prop = randomData.nextUniform(lastProp, 1); + } else { // Random jump toward 0 + prop = randomData.nextUniform(0, lastProp); + } + // Make sure sequence is monotone + if (rampingUp) { + mean = Math.min(lastMean, top - doubleDelay * prop); + } else { + mean = Math.max(lastMean, top - doubleDelay * prop); + } + } + } + + // Remember last mean for ramp up / down + lastMean = mean; + + // Generate and return random deviate + if (delayType.equals("gaussian")) { + return Math.round(randomData.nextGaussian(mean, sigma)); + } else { // must be Poisson + return Math.round(randomData.nextPoisson(mean)); + } + } + } + +} Added: jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ConfigurationException.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ConfigurationException.java?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ConfigurationException.java (added) +++ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/ConfigurationException.java Mon Jul 16 23:11:36 2007 @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.performance.dbcp; + +public class ConfigurationException extends Exception { + + public ConfigurationException() { + super(); + } + + public ConfigurationException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public ConfigurationException(String arg0) { + super(arg0); + } + + public ConfigurationException(Throwable arg0) { + super(arg0); + } + +} Added: jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPClientThread.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPClientThread.java?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPClientThread.java (added) +++ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPClientThread.java Mon Jul 16 23:11:36 2007 @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.performance.dbcp; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.List; +import java.util.logging.Logger; +import javax.sql.DataSource; + +import org.apache.commons.math.stat.descriptive.SummaryStatistics; +import org.apache.commons.performance.ClientThread; + +/** + * Client thread that executes requests in a loop using a configured DataSource, + * with number of requests, time between requests and query strings governed by + * constructor parameters. See ClientThread javadoc for a description + * of how times between requests are computed. + * + */ +public class DBCPClientThread extends ClientThread { + /** Initial segment of query string */ + private String queryString; + /** Whether or not the query is on the text column */ + private boolean textQuery = false; + /** DataSource used to connect */ + private DataSource dataSource = null; + /** Database connection */ + Connection conn = null; + /** Current query */ + String currentQuery = null; + + /** + * Create a dbcp client thread. + * + * @param iterations number of iterations + * @param delay mean time between client requests + * @param delayType distribution of time between client requests + * @param queryType type of query + * @param period period of cycle for cyclic load + * @param cycleType type of cycle for mean delay + * @param logger common logger shared by all clients + * @param dataSource DataSource for connections + * @param statsList List of SummaryStatistics to add results to + */ + public DBCPClientThread(long iterations, long delay, double sigma, + String delayType, String queryType, long period, String cycleType, + String rampType, Logger logger, DataSource dataSource, + List <SummaryStatistics> statsList) { + + super(iterations, delay, sigma, delayType, period, cycleType, + rampType, logger, statsList); + + this.dataSource = dataSource; + + if (queryType.equals("integerIndexed")) { + queryString = "select * from test_table WHERE indexed="; + } else if (queryType.equals("integerScan")) { + queryString = "select * from test_table WHERE not_indexed="; + } else { + queryString = "select * from test_table WHERE text='"; + textQuery = true; + } + } + + /** Generate a random query */ + public void setup() throws Exception { + if (textQuery) { + currentQuery = queryString + + randomData.nextHexString(20) + "';"; + } else { + currentQuery = queryString + + randomData.nextInt(0, 100) + ";"; + } + } + + /** Execute query */ + public void execute() throws Exception { + conn = dataSource.getConnection(); + Statement stmt = conn.createStatement(); + stmt.execute(currentQuery); + ResultSet rs = stmt.getResultSet(); + if (!rs.isAfterLast()) { + rs.next(); + } + rs.close(); + stmt.close(); + } + + /** Close connection */ + public void cleanUp() throws Exception { + conn.close(); + } + +} Added: jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java (added) +++ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java Mon Jul 16 23:11:36 2007 @@ -0,0 +1,415 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.performance.dbcp; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp.AbandonedConfig; +import org.apache.commons.dbcp.AbandonedObjectPool; +import org.apache.commons.dbcp.ConnectionFactory; +import org.apache.commons.dbcp.DataSourceConnectionFactory; +import org.apache.commons.dbcp.DriverConnectionFactory; +import org.apache.commons.dbcp.DriverManagerConnectionFactory; +import org.apache.commons.dbcp.PoolableConnectionFactory; +import org.apache.commons.dbcp.PoolingDataSource; +import org.apache.commons.digester.Digester; +import org.apache.commons.pool.KeyedObjectPoolFactory; +import org.apache.commons.pool.PoolableObjectFactory; +import org.apache.commons.pool.impl.GenericKeyedObjectPool; +import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.math.random.RandomData; +import org.apache.commons.math.random.RandomDataImpl; +import org.apache.commons.math.stat.descriptive.SummaryStatistics; +import org.apache.commons.math.stat.descriptive.SummaryStatisticsImpl; + +/** + * Configurable load / performance tester for commons dbcp. + * Uses Commons Digester to parse and load configuration and spawns + * DBCPClientThread instances to generate load and gather statistics. + * + */ +public class DBCPSoak { + private static Logger logger = Logger.getLogger(DBCPSoak.class.getName()); + private static List <SummaryStatistics> statsList = + new ArrayList <SummaryStatistics>(); + private String driverClass; + private String connectUrl; + private String connectUser; + private String connectPassword; + private String poolType; + private String driverType; + private String factoryType; + private GenericObjectPool connectionPool; + private PoolingDataSource dataSource; + private long numClients; + private long iterations; + private int maxActive; + private int maxIdle; + private int minIdle; + private long maxWait; + private long delay; + private double sigma; + private String delayType; + private String queryType; + private String rampType; + private long period; + private String cycleType; + private boolean autocommit; + private boolean readOnly; + private byte exhaustedAction; + private boolean testOnBorrow; + private boolean testOnReturn; + private long timeBetweenEvictions; + private int testsPerEviction; + private long idleTimeout; + private boolean testWhileIdle; + private String validationQuery; + private AbandonedConfig abandonedConfig = new AbandonedConfig(); + private boolean poolPreparedStatements; + private int maxOpenStatements; + + public void execute() throws Exception { + Class.forName(driverClass); + + // Create object pool + if (poolType.equals("GenericObjectPool")) { + connectionPool = new GenericObjectPool( + null, maxActive, exhaustedAction, + maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn, + timeBetweenEvictions, testsPerEviction, idleTimeout, + testWhileIdle); + } else if (poolType.equals("AbandonedObjectPool")) { + connectionPool = new AbandonedObjectPool(null,abandonedConfig); + } else { + throw new ConfigurationException( + "invalid pool type configuration: " + poolType); + } + + // Create raw connection factory + ConnectionFactory connectionFactory = null; + if (driverType.equals("DriverManager")) { + connectionFactory = new DriverManagerConnectionFactory( + connectUrl,connectUser, + connectPassword); + } else if (driverType.equals("Driver")) { + Properties props = new Properties(); + props.put("user", connectUser); + props.put("password", connectPassword); + connectionFactory = new DriverConnectionFactory( + (Driver) Class.forName(driverClass).newInstance(), + connectUrl, props); + } else { + throw new ConfigurationException( + "Bad config setting for driver type"); + } + + // Create object factory + PoolableObjectFactory poolableConnectionFactory = null; + KeyedObjectPoolFactory statementPoolFactory = null; + if (poolPreparedStatements) { // Use same defaults as BasicDataSource + statementPoolFactory = new GenericKeyedObjectPoolFactory(null, + -1, // unlimited maxActive (per key) + GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL, + 0, // maxWait + 1, // maxIdle (per key) + maxOpenStatements); //TODO: make all configurable + } + if (factoryType.equals("PoolableConnectionFactory")) { + poolableConnectionFactory = + new PoolableConnectionFactory( + connectionFactory,connectionPool, statementPoolFactory, + validationQuery, readOnly, autocommit); + } else if (factoryType.equals("CPDSConnectionFactory")) { + throw new ConfigurationException( + "CPDSConnectionFactory not implemented yet"); + } else { + throw new ConfigurationException( + "Invalid factory type: " + factoryType); + } + + // Create DataSource + dataSource = new PoolingDataSource(connectionPool); + + // Try to connect and query test_table. If "test_table" appears in + // exception message, assume table needs to be created. + Connection conn = dataSource.getConnection(); + try { + Statement stmnt = conn.createStatement(); + stmnt.execute("select * from test_table where indexed=1;"); + stmnt.close(); + } catch (Exception ex) { + if (ex.getMessage().indexOf("test_table") > 0) { + logger.info("Creating test_table"); + makeTable(); + logger.info("test_table created successfully"); + } else { + throw ex; + } + } finally { + conn.close(); + } + + logger.info("Starting"); + + // Spawn and execute client threads + ExecutorService ex = Executors.newFixedThreadPool((int)numClients); + for (int i = 0; i < numClients; i++) { + ex.execute(new DBCPClientThread(iterations, delay, sigma, delayType, + queryType, period, cycleType, rampType, logger, + dataSource, statsList)); + } + ex.shutdown(); + // hard time limit of one day for now + // TODO: make this configurable + ex.awaitTermination(60 * 60 * 24, TimeUnit.SECONDS); + + // Compute summary statistics + SummaryStatistics meanSummary = new SummaryStatisticsImpl(); + SummaryStatistics stdSummary = new SummaryStatisticsImpl(); + SummaryStatistics minSummary = new SummaryStatisticsImpl(); + SummaryStatistics maxSummary = new SummaryStatisticsImpl(); + for (int i = 0; i < statsList.size(); i++) { + SummaryStatistics stats = (SummaryStatistics) statsList.get(i); + meanSummary.addValue(stats.getMean()); + stdSummary.addValue(stats.getStandardDeviation()); + minSummary.addValue(stats.getMin()); + maxSummary.addValue(stats.getMax()); + } + logger.info("Overall statistics for the mean"); + logger.info(meanSummary.toString()); + logger.info("Overall statistics for the standard deviation"); + logger.info(stdSummary.toString()); + logger.info("Overall statistics for the min"); + logger.info(minSummary.toString()); + logger.info("Overall statistics for the max"); + logger.info(maxSummary.toString()); + } + + public void configureDataBase(String driver, String url, + String username, String password) { + this.driverClass = driver; + this.connectUrl = url; + this.connectUser = username; + this.connectPassword = password; + } + + public void configureConnectionFactory(String type, + String autoCommit, String readOnly, String validationQuery) { + this.driverType = type; + this.autocommit = Boolean.parseBoolean(autoCommit); + this.readOnly = Boolean.parseBoolean(readOnly); + this.validationQuery = validationQuery; + } + + public void configurePoolableConnectionFactory(String type, + String poolPreparedStatements, String maxOpenStatements) { + this.factoryType = type; + this.poolPreparedStatements = + Boolean.parseBoolean(poolPreparedStatements); + this.maxOpenStatements = Integer.parseInt(maxOpenStatements); + } + + public void configurePool(String maxActive, String maxIdle, String minIdle, + String maxWait, String exhaustedAction, String testOnBorrow, + String testOnReturn, String timeBetweenEvictions, + String testsPerEviction, String idleTimeout, + String testWhileIdle, String type) throws ConfigurationException { + this.maxActive = Integer.parseInt(maxActive); + this.maxIdle = Integer.parseInt(maxIdle); + this.maxWait = Long.parseLong(maxWait); + this.testOnBorrow = Boolean.parseBoolean(testOnBorrow); + this.testOnReturn = Boolean.parseBoolean(testOnReturn); + this.timeBetweenEvictions = Long.parseLong(timeBetweenEvictions); + this.testsPerEviction = Integer.parseInt(testsPerEviction); + this.idleTimeout = Long.parseLong(idleTimeout); + this.testWhileIdle = Boolean.parseBoolean(testWhileIdle); + this.poolType = type; + if (exhaustedAction.equals("block")) { + this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK; + } else if (exhaustedAction.equals("fail")) { + this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_FAIL; + } else if (exhaustedAction.equals("grow")) { + this.exhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; + } else { + throw new ConfigurationException( + "Bad configuration setting for exhausted action: " + + exhaustedAction); + } + } + + public void configureAbandonedConfig(String logAbandoned, + String removeAbandoned, String abandonedTimeout) { + abandonedConfig.setLogAbandoned(Boolean.parseBoolean(logAbandoned)); + abandonedConfig.setRemoveAbandoned( + Boolean.parseBoolean(removeAbandoned)); + abandonedConfig.setRemoveAbandonedTimeout( + Integer.parseInt(abandonedTimeout)); + } + + public void configureRun(String queryType, String iterations, + String clients, String delay, String sigma, String delayType, + String rampType, String period, String cycleType) + throws ConfigurationException { + this.queryType = queryType; + this.iterations = Long.parseLong(iterations); + this.numClients = Long.parseLong(clients); + this.delay = Long.parseLong(delay); + this.sigma = Double.parseDouble(sigma); + this.delayType = delayType; + this.rampType = rampType; + this.period = Long.parseLong(period); + this.cycleType = cycleType; + if (cycleType.equals("oscillating") && this.period <= 0) { + throw new ConfigurationException( + "Period must be positive for oscillating cycle type"); + } + } + + private void makeTable() throws Exception { + Class.forName(driverClass); + Connection db = DriverManager.getConnection(connectUrl,connectUser, + connectPassword); + try { + Statement sql = db.createStatement(); + String sqlText = + "create table test_table (indexed int, text varchar(20)," + + " not_indexed int)"; + sql.executeUpdate(sqlText); + sqlText = "CREATE INDEX test1_id_index ON test_table (indexed);"; + sql.executeUpdate(sqlText); + RandomData randomData = new RandomDataImpl(); + for (int i = 0; i < 10000; i++) { + int indexed = randomData.nextInt(0, 100); + int not_indexed = randomData.nextInt(0, 1000); + String text = randomData.nextHexString(20); + sqlText = + "INSERT INTO test_table (indexed, text, not_indexed)" + + "VALUES (" + indexed + "," + "'"+ text + "'," + + not_indexed + ");"; + sql.executeUpdate(sqlText); + } + sql.close(); + } finally { + db.close(); + } + } + + public void configure() throws Exception { + Digester digester = new Digester(); + digester.push(this); + + digester.addCallMethod("configuration/database", + "configureDataBase", 4); + digester.addCallParam("configuration/database/driver", 0); + digester.addCallParam("configuration/database/url", 1); + digester.addCallParam("configuration/database/username", 2); + digester.addCallParam("configuration/database/password", 3); + + digester.addCallMethod("configuration/connection-factory", + "configureConnectionFactory", 4); + digester.addCallParam( + "configuration/connection-factory/type", 0); + digester.addCallParam( + "configuration/connection-factory/auto-commit", 1); + digester.addCallParam( + "configuration/connection-factory/read-only", 2); + digester.addCallParam( + "configuration/connection-factory/validation-query", 3); + + digester.addCallMethod("configuration/poolable-connection-factory", + "configurePoolableConnectionFactory", 3); + digester.addCallParam( + "configuration/poolable-connection-factory/type", 0); + digester.addCallParam( + "configuration/poolable-connection-factory/pool-prepared-statements", 1); + digester.addCallParam( + "configuration/poolable-connection-factory/max-open-statements", 2); + + digester.addCallMethod("configuration/pool", + "configurePool", 12); + digester.addCallParam( + "configuration/pool/max-active", 0); + digester.addCallParam( + "configuration/pool/max-idle", 1); + digester.addCallParam( + "configuration/pool/min-idle", 2); + digester.addCallParam( + "configuration/pool/max-wait", 3); + digester.addCallParam( + "configuration/pool/exhausted-action", 4); + digester.addCallParam( + "configuration/pool/test-on-borrow", 5); + digester.addCallParam( + "configuration/pool/test-on-return", 6); + digester.addCallParam( + "configuration/pool/time-between-evictions", 7); + digester.addCallParam( + "configuration/pool/tests-per-eviction", 8); + digester.addCallParam( + "configuration/pool/idle-timeout", 9); + digester.addCallParam( + "configuration/pool/test-while-idle", 10); + digester.addCallParam( + "configuration/pool/type", 11); + + digester.addCallMethod("configuration/run", + "configureRun", 9); + digester.addCallParam( + "configuration/run/query-type", 0); + digester.addCallParam( + "configuration/run/iterations", 1); + digester.addCallParam( + "configuration/run/clients", 2); + digester.addCallParam( + "configuration/run/delay-mean", 3); + digester.addCallParam( + "configuration/run/delay-sigma", 4); + digester.addCallParam( + "configuration/run/delay-type", 5); + digester.addCallParam( + "configuration/run/ramp-type", 6); + digester.addCallParam( + "configuration/run/period", 7); + digester.addCallParam( + "configuration/run/cycle-type", 8); + + digester.addCallMethod("configuration/abandoned-config", + "configureAbandonedConfig", 3); + digester.addCallParam( + "configuration/abandoned-config/log-abandoned", 0); + digester.addCallParam( + "configuration/abandoned-config/remove-abandoned", 1); + digester.addCallParam( + "configuration/abandoned-config/abandoned-timeout", 2); + + digester.parse("/home/phil/dbcpTest/config.xml"); + + } +} Added: jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPTest.java?view=auto&rev=556823 ============================================================================== --- jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPTest.java (added) +++ jakarta/commons/sandbox/performance/src/java/org/apache/commons/performance/dbcp/DBCPTest.java Mon Jul 16 23:11:36 2007 @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.performance.dbcp; + +/** + * Load / performance test runner. + * + */ +public class DBCPTest { + private static DBCPSoak soaker = new DBCPSoak(); + public static void main(String[] args) { + try { + soaker.configure(); + soaker.execute(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]