/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. The MySQL Connector/J is licensed under the terms of the GPLv2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors. There are special exceptions to the terms and conditions of the GPLv2 as it is applied to this software, see the FLOSS License Exception <http://www.mysql.com/about/legal/licensing/foss-exception.html>. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package testsuite.regression; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Properties; import testsuite.BaseTestCase; /** * Tests for multi-thread stress regressions. * * @author Mark Matthews * @version $Id: StressRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38 * mmatthews Exp $ */ public class StressRegressionTest extends BaseTestCase { private int numThreadsStarted; /** * Creates a new StressRegressionTest * * @param name * the name of the test. */ public StressRegressionTest(String name) { super(name); } /** * Runs all test cases in this test suite * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(StressRegressionTest.class); } /** * * * @throws Exception * ... */ public synchronized void testContention() throws Exception { if (false) { System.out.println("Calculating baseline elapsed time..."); long start = System.currentTimeMillis(); contentiousWork(this.conn, this.stmt, 0); long singleThreadElapsedTimeMillis = System.currentTimeMillis() - start; System.out.println("Single threaded execution took " + singleThreadElapsedTimeMillis + " ms."); int numThreadsToStart = 95; System.out.println("\nStarting " + numThreadsToStart + " threads."); this.numThreadsStarted = numThreadsToStart; ContentionThread[] threads = new ContentionThread[this.numThreadsStarted]; for (int i = 0; i < numThreadsToStart; i++) { threads[i] = new ContentionThread(i); threads[i].start(); } for (;;) { try { wait(); if (this.numThreadsStarted == 0) { break; } } catch (InterruptedException ie) { // ignore } } // Collect statistics... System.out.println("Done!"); double avgElapsedTimeMillis = 0; List<Long> elapsedTimes = new ArrayList<Long>(); for (int i = 0; i < numThreadsToStart; i++) { elapsedTimes.add(new Long(threads[i].elapsedTimeMillis)); avgElapsedTimeMillis += ((double) threads[i].elapsedTimeMillis / numThreadsToStart); } Collections.sort(elapsedTimes); System.out.println("Average elapsed time per-thread was " + avgElapsedTimeMillis + " ms."); System.out.println("Median elapsed time per-thread was " + elapsedTimes.get(elapsedTimes.size() / 2) + " ms."); System.out.println("Minimum elapsed time per-thread was " + elapsedTimes.get(0) + " ms."); System.out.println("Maximum elapsed time per-thread was " + elapsedTimes.get(elapsedTimes.size() - 1) + " ms."); } } /** * * * @throws Exception * ... */ public void testCreateConnections() throws Exception { new CreateThread().start(); } /** * * * @throws Exception * ... */ public void testCreateConnectionsUnderLoad() throws Exception { new CreateThread(new BusyThread()).start(); } /** * * @param threadConn * @param threadStmt * @param threadNumber */ void contentiousWork(Connection threadConn, Statement threadStmt, int threadNumber) { Date now = new Date(); try { for (int i = 0; i < 1000; i++) { ResultSet threadRs = threadStmt.executeQuery("SELECT 1, 2"); while (threadRs.next()) { threadRs.getString(1); threadRs.getString(2); } threadRs.close(); PreparedStatement pStmt = threadConn .prepareStatement("SELECT ?"); pStmt.setTimestamp(1, new Timestamp(now.getTime())); threadRs = pStmt.executeQuery(); while (threadRs.next()) { threadRs.getTimestamp(1); } threadRs.close(); pStmt.close(); } } catch (Exception ex) { throw new RuntimeException(ex.toString()); } } synchronized void reportDone() { // TODO: This test should just be refactored to use an executor and futures. //this.numThreadsStarted--; notify(); } public class BusyThread extends Thread { boolean stop = false; public void run() { while (!this.stop) { } } } class ContentionThread extends Thread { Connection threadConn; Statement threadStmt; int threadNumber; long elapsedTimeMillis; public ContentionThread(int num) throws SQLException { this.threadNumber = num; this.threadConn = getConnectionWithProps(new Properties()); this.threadStmt = this.threadConn.createStatement(); System.out.println(this.threadConn); } public void run() { long start = System.currentTimeMillis(); try { contentiousWork(this.threadConn, this.threadStmt, this.threadNumber); this.elapsedTimeMillis = System.currentTimeMillis() - start; System.out .println("Thread " + this.threadNumber + " finished."); } finally { if (this.elapsedTimeMillis == 0) { this.elapsedTimeMillis = System.currentTimeMillis() - start; } reportDone(); try { this.threadStmt.close(); this.threadConn.close(); } catch (SQLException ex) { // ignore } } } } class CreateThread extends Thread { BusyThread busyThread; int numConnections = 15; public CreateThread() { } public CreateThread(BusyThread toStop) { this.busyThread = toStop; } public CreateThread(int numConns) { this.numConnections = numConns; } public void run() { try { Connection[] connList = new Connection[this.numConnections]; long maxConnTime = Long.MIN_VALUE; long minConnTime = Long.MAX_VALUE; double averageTime = 0; Properties nullProps = new Properties(); for (int i = 0; i < this.numConnections; i++) { long startTime = System.currentTimeMillis(); connList[i] = getConnectionWithProps(nullProps); long endTime = System.currentTimeMillis(); long ellapsedTime = endTime - startTime; if (ellapsedTime < minConnTime) { minConnTime = ellapsedTime; } if (ellapsedTime > maxConnTime) { maxConnTime = ellapsedTime; } averageTime += ((double) ellapsedTime / this.numConnections); } if (this.busyThread != null) { this.busyThread.stop = true; } for (int i = 0; i < this.numConnections; i++) { connList[i].close(); } System.out.println(minConnTime + "/" + maxConnTime + "/" + averageTime); } catch (Exception ex) { throw new RuntimeException(ex); } } } }