| /* |
| * |
| * Derby - Class org.apache.derbyTesting.system.sttest.Sttest |
| * |
| * 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.derbyTesting.system.sttest; |
| |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.sql.CallableStatement; |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.Properties; |
| import java.util.Random; |
| |
| import org.apache.derby.tools.JDBCDisplayUtil; |
| import org.apache.derby.tools.ij; |
| import org.apache.derbyTesting.system.sttest.tools.MemCheck; |
| import org.apache.derbyTesting.system.sttest.utils.Datatypes; |
| import org.apache.derbyTesting.system.sttest.utils.Setup; |
| import org.apache.derbyTesting.system.sttest.utils.StStatus; |
| |
| /* |
| * * Sttest.java * 'Sttest' is short for 'single table test.' Sttest.java |
| * supplies * the main entry point and the top level code for controlling the * |
| * actions of the test, including the ddl for the table and indexes. * The |
| * purpose of the test is to exercise the store code by running * updates on the |
| * single table for an indefinitely long time, with * an indefinitely large |
| * number of user connections, each randomly * executing one of a small number |
| * of update procedures with random * data. The test sets a minimum and maximum |
| * number of rows, builds * the table up to the minimum number of rows, and from |
| * that point * either gradually grows the table to the max size, or gradually * |
| * shrinks it to the min size. Periodically memory use is reported, * and the |
| * table is compressed, to keep performance from deteriorating. |
| */ |
| public class Sttest extends Thread { |
| |
| static int loops = 200; |
| |
| static int rowcount = 0; |
| |
| static int testcount = 0; |
| |
| static int connections_to_make = 250; |
| |
| static Random rand; |
| |
| static boolean increase = true; |
| |
| static boolean not_finished = true; |
| |
| static int targetmax = 100000; // build up to 1GB database |
| |
| static int targetmin = 90000; |
| |
| static int insertsize = 7; |
| |
| static int updatesize = 1; |
| |
| static int deletesize = 1; |
| |
| static boolean fatal = false; |
| |
| static int rows = 0; |
| |
| static boolean countlock = false; |
| |
| static int delete_freq = 1; |
| |
| static int locker_id = -1; |
| |
| static final int INIT = 0; |
| |
| static final int GROW = 1; |
| |
| static final int SHRINK = 2; |
| |
| static int mode = INIT; |
| |
| static int count_timer = 0; |
| |
| static int inserts_to_try = 0; |
| |
| static final int INITIAL_CONNECTIONS = 2; // initial connections should be |
| |
| // low, otherwise deadlock will |
| // happen. |
| |
| static boolean startByIJ = false; |
| |
| static String dbURL = "jdbc:derby:testDB"; |
| |
| static String driver = "org.apache.derby.jdbc.EmbeddedDriver"; |
| |
| static StStatus status = null; |
| |
| int thread_id; |
| |
| int ind = 0; |
| |
| public static void main(String[] args) throws SQLException, IOException, |
| InterruptedException, Exception, Throwable { |
| System.getProperties().put("derby.locks.deadlockTimeout", "60"); |
| System.getProperties().put("derby.locks.waitTimeout", "200"); |
| System.out.println("Test Sttest starting"); |
| System.getProperties().put("derby.infolog.append", "true"); |
| System.getProperties().put("derby.stream.error.logSeverityLevel", "0"); |
| // get any properties user may have set in Sttest.properties file |
| // these will override any of those set above |
| userProperties(); |
| Class<?> clazz = Class.forName(driver); |
| clazz.getConstructor().newInstance(); |
| if (Setup.doit(dbURL) == false) |
| System.exit(1); |
| status = new StStatus(); |
| sttTop(); |
| } |
| |
| static void userProperties() throws Throwable { |
| FileInputStream fileIn = null; |
| try { |
| fileIn = new FileInputStream("Sttest.properties"); |
| } catch (Exception e) { |
| System.out |
| .println("user control file 'Sttest.properties' not found; using defaults"); |
| } |
| if (fileIn != null) { |
| Properties props = new Properties(); |
| props.load(fileIn); |
| fileIn.close(); |
| String prop = null; |
| prop = props.getProperty("connections"); |
| if (prop != null) |
| connections_to_make = Integer.parseInt(prop); |
| prop = props.getProperty("dbURL"); |
| if (prop != null) |
| dbURL = prop; |
| prop = props.getProperty("driver"); |
| if (prop != null) |
| driver = prop; |
| // allows us to get any other properties into the system |
| Properties sysprops = System.getProperties(); |
| Enumeration list = props.propertyNames(); |
| String s = null; |
| while (list.hasMoreElements()) { |
| s = (String) list.nextElement(); |
| sysprops.put(s, props.getProperty(s)); |
| } |
| } |
| System.out.println("driver = " + driver); |
| System.out.println("dbURL = " + dbURL); |
| System.out.println("connections = " + connections_to_make); |
| } |
| |
| public static void sttTop() throws SQLException, IOException, |
| InterruptedException, Exception, Throwable { |
| rand = new Random(); |
| |
| Datatypes.Rn = rand; |
| // harder to actually delete rows when there are |
| // more connections, so repeat operation more often |
| delete_freq = 1 + connections_to_make % 5; |
| initial_data(); |
| Date d = new Date(); |
| status.firstMessage(connections_to_make, d); |
| // check memory in separate thread-- allows us to monitor |
| // usage during database calls |
| // 200,000 msec = 3min, 20 sec delay between checks |
| MemCheck mc = new MemCheck(200000); |
| mc.start(); |
| Sttest testsessions[] = new Sttest[connections_to_make]; |
| for (int i = 0; i < connections_to_make; i++) { |
| testsessions[i] = new Sttest(i); |
| testsessions[i].start(); |
| sleep(3000); |
| } |
| for (int i = 0; i < connections_to_make; i++) { |
| testsessions[i].join(); |
| } |
| try { |
| mc.stopNow = true; |
| mc.join(); |
| } catch (Throwable t) { |
| throw (t); |
| } |
| } |
| |
| Sttest(int num) throws SQLException { |
| this.thread_id = num; |
| } |
| |
| static synchronized void reset_loops(int myloopcount) { |
| if (myloopcount == loops) |
| loops--; |
| // otherwise some other thread got there first and reset it |
| } |
| |
| // available to force synchronization of get_countlock(), ... |
| static synchronized void locksync() { |
| return; |
| } |
| |
| static synchronized boolean get_countlock() { |
| locksync(); |
| return (countlock); |
| } |
| |
| static synchronized boolean set_countlock(boolean state) { |
| locksync(); |
| if (state == true && countlock == true) |
| return (false); |
| countlock = state; |
| return (true); |
| } |
| |
| static synchronized void changerowcount(int in) { |
| rowcount += in; |
| } |
| |
| static synchronized void changerowcount2zero() { |
| rowcount = 0; |
| } |
| |
| static void initial_data() throws Exception, Throwable { |
| Connection conn = null; |
| int rows = 0; |
| try { |
| conn = mystartJBMS(); |
| } catch (Throwable t) { |
| throw (t); |
| } |
| // our goal is to get up to minimum table size |
| int x = Datatypes.get_table_count(conn); |
| if (x != -1) { |
| rows = x; |
| } |
| if (conn != null) { |
| conn.commit(); |
| conn.close(); |
| } |
| rowcount = rows; |
| if (rows >= targetmin) { |
| mode = GROW; |
| System.out.println("initial data not needed"); |
| return; |
| } |
| inserts_to_try = targetmin - rows; |
| Sttest testthreads[] = new Sttest[INITIAL_CONNECTIONS]; |
| for (int i = 0; i < INITIAL_CONNECTIONS; i++) { |
| testthreads[i] = new Sttest(i); |
| testthreads[i].start(); |
| } |
| for (int i = 0; i < INITIAL_CONNECTIONS; i++) { |
| testthreads[i].join(); |
| } |
| mode = GROW; |
| System.out.println("complete initial data"); |
| return; |
| } |
| |
| public void run() { |
| Connection conn = null; |
| Date d = null; |
| try { |
| conn = mystartJBMS(); |
| } catch (Throwable t) { |
| return; |
| } |
| int ind2 = 0; |
| int myloops = loops; |
| while (not_finished) { |
| if (loops <= 0) |
| break;// done |
| // thread-private copy to be checked against global copy |
| // before attempting to update |
| myloops = loops; |
| if (fatal == true) |
| break; |
| if (mode == INIT && inserts_to_try <= 0) { |
| break; |
| } |
| // test rowcount |
| if (mode == GROW && rowcount > targetmax) { |
| System.out.println("hit targetmax with " + rowcount + " " + d); |
| d = new Date(); |
| mode = SHRINK; |
| reset_loops(myloops); |
| insertsize = 1; |
| deletesize = 12; |
| if (set_countlock(true) == true) { |
| try { |
| checkrowcount(conn); |
| MemCheck.showmem(); |
| status.updateStatus(); |
| } catch (Exception e) { |
| System.out.println("unexpected exception in rowcount"); |
| set_countlock(false); |
| System.exit(1); |
| } |
| MemCheck.showmem(); |
| } |
| set_countlock(false); |
| yield(); |
| } else if (mode == GROW && rowcount >= targetmax) { |
| d = new Date(); |
| System.out.println("hit targetmax with " + rowcount + " " + d); |
| mode = SHRINK; |
| insertsize = 1; |
| deletesize = 12; |
| } else if (mode == SHRINK && rowcount <= targetmin) { |
| d = new Date(); |
| System.out.println("hit targetmin with " + rowcount + " " + d); |
| mode = GROW; |
| reset_loops(myloops); |
| insertsize = 8; |
| deletesize = 1; |
| if (set_countlock(true) == true) { |
| try { |
| checkrowcount(conn); |
| MemCheck.showmem(); |
| status.updateStatus(); |
| } catch (Exception e) { |
| System.out.println("unexpected exception in rowcount"); |
| set_countlock(false); |
| System.exit(1); |
| } |
| MemCheck.showmem(); |
| // compress |
| try { |
| compress(conn); |
| } catch (Exception e) { |
| System.out.println("unexpected exception during compress"); |
| } |
| } |
| set_countlock(false); |
| yield(); |
| } |
| // don't interfere with count query |
| while (get_countlock() == true) { |
| try { |
| sleep(1000); |
| } catch (java.lang.InterruptedException ex) { |
| System.out.println("unexpected sleep interruption"); |
| break; |
| } |
| } |
| try { |
| if (mode == INIT) |
| ind = 0; |
| else |
| ind = Math.abs(rand.nextInt() % 3); |
| switch (ind) { |
| case 0: |
| ind2 = Math.abs(rand.nextInt() % insertsize); |
| int addrows = 0; |
| for (int i = 0; i <= ind2; i++) { |
| Datatypes.add_one_row(conn, thread_id); |
| addrows++; |
| conn.commit(); |
| if (mode == INIT) { |
| inserts_to_try--; |
| } |
| yield(); |
| changerowcount(1); |
| } |
| System.out.println(addrows + " Rows inserted"); |
| break; |
| case 1: |
| ind2 = Math.abs(rand.nextInt() % updatesize); |
| int updaterow = 0; |
| for (int i = 0; i <= ind2; i++) { |
| Datatypes.update_one_row(conn, thread_id); |
| updaterow++; |
| conn.commit(); |
| yield(); |
| } |
| System.out.println(updaterow + " rows updated"); |
| break; |
| case 2: |
| ind2 = Math.abs(rand.nextInt() % deletesize); |
| int del_rows = 0; |
| del_rows = Datatypes.delete_some(conn, thread_id, ind2 + 1); |
| yield(); |
| changerowcount(-1 * del_rows); |
| // commits are done inside delete_some() |
| System.out.println(del_rows + " rows deleted"); |
| break; |
| } // end switch |
| |
| } catch (SQLException se) { |
| if (se.getSQLState() == null) |
| se.printStackTrace(); |
| if (se.getSQLState().equals("40001")) { |
| System.out.println("t" + thread_id + " deadlock op = " |
| + ind); |
| continue; |
| } |
| if (se.getSQLState().equals("40XL1")) { |
| System.out |
| .println("t" + thread_id + " timeout op = " + ind); |
| continue; |
| } |
| if (se.getSQLState().equals("23500")) { |
| System.out.println("t" + thread_id |
| + " duplicate key violation\n"); |
| continue; |
| } |
| if (se.getSQLState().equals("23505")) { |
| System.out.println("t" + thread_id |
| + " duplicate key violation\n"); |
| continue; |
| } |
| System.out.println("t" + thread_id |
| + " FAIL -- unexpected exception:"); |
| JDBCDisplayUtil.ShowException(System.out, se); |
| fatal = true; |
| break; |
| } catch (Throwable e) { |
| e.printStackTrace(); |
| if (e.getMessage().equals("java.lang.ThreadDeath")) { |
| System.out.println("caught threaddeath and continuing\n"); |
| } else { |
| fatal = true; |
| e.printStackTrace(); |
| } |
| } |
| }// end while |
| try { |
| conn.close(); |
| } catch (Throwable e) { |
| e.printStackTrace(); |
| } |
| System.out.println("Thread finished: " + thread_id); |
| } |
| |
| static synchronized void checkrowcount(Connection conn) |
| throws java.lang.Exception { |
| int x = Datatypes.get_table_count(conn); |
| if (x == -1) { // count timed itself out |
| System.out.println("table count timed out"); |
| } else { |
| System.out.println("rowcount by select: " + x |
| + " client rowcount = " + rowcount); |
| changerowcount(x - rowcount); |
| } |
| conn.commit(); |
| } |
| |
| static public Connection mystartJBMS() throws Throwable { |
| Connection conn = null; |
| if (startByIJ == true) { |
| conn = ij.startJBMS(); |
| } else |
| try { |
| conn = DriverManager.getConnection(dbURL + ";create=false"); |
| conn.setAutoCommit(false); |
| conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); |
| } catch (SQLException se) { |
| System.out.println("connect failed for " + dbURL); |
| JDBCDisplayUtil.ShowException(System.out, se); |
| } |
| return (conn); |
| } |
| |
| static synchronized void compress(Connection conn) |
| throws java.lang.Exception { |
| System.out.println("compressing table"); |
| boolean autocom = conn.getAutoCommit(); |
| try { |
| conn.setAutoCommit(true); |
| CallableStatement cs = conn.prepareCall( |
| "CALL SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(?, ?, ?, ?, ?)"); |
| cs.setString(1, "APP"); |
| cs.setString(2, "DATATYPES"); |
| cs.setShort(3, (short) 1); |
| cs.setShort(4, (short) 1); |
| cs.setShort(5, (short) 1); |
| cs.execute(); |
| cs.close(); |
| } catch (SQLException se) { |
| System.out.println("compress table: FAIL -- unexpected exception:"); |
| JDBCDisplayUtil.ShowException(System.out, se); |
| se.printStackTrace(); |
| } |
| conn.setAutoCommit(autocom); |
| } |
| } |