package hrdb.tests; import java.sql.*; import java.util.*; public class BugTest implements Runnable { static final String tabledef = "CREATE TABLE order_table ( o_id integer not null, o_d_id integer not null, o_w_id integer not null, o_c_id integer, o_entry_d timestamp, o_carrier_id integer, o_ol_cnt integer, o_all_local integer, primary key (o_w_id, o_d_id, o_id)) ENGINE=InnoDB"; static int oid = 0; static String[] progress = {".",",",":","/","\\","!","<",">","?","\"","{","}","[","]","=","+","-","_"}; int id,iso; String connect; static int[] isolevels = {Connection.TRANSACTION_READ_UNCOMMITTED,Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ,Connection.TRANSACTION_SERIALIZABLE}; public static void main(String[] args) { if (args.length < 3) { System.out.println("java hrdb.tests.BugTest "); System.out.println(" iso: 1 = READ_UNCOMMITTED, 2 = READ_COMMITTED,"); System.out.println(" 3 = REPEATABLE_READ, 4 = SERIALIZABLE"); return; } String connect = args[0]; String jdbcdriver = args[1]; int conc = Integer.parseInt(args[2]); int iso = isolevels[args.length > 3 ? Integer.parseInt(args[3])-1 : 3]; try { Class.forName(jdbcdriver); //load driver Connection c = DriverManager.getConnection(connect); c.setTransactionIsolation(iso); c.setAutoCommit(false); Statement s = c.createStatement(); s.executeUpdate("delete from order_table"); //empty table c.commit(); s.close(); c.close(); } catch (Exception e) { e.printStackTrace(); return; } for (int i=0; i < conc; i++) { new Thread(new BugTest(i,connect,iso)).start(); } } public BugTest(int i,String connect, int iso) { this.id = i; this.connect = connect; this.iso = iso; } public void run() { try { Connection conn = DriverManager.getConnection(connect); conn.setTransactionIsolation(iso); conn.setAutoCommit(false); Statement s = conn.createStatement(); Random rand = new Random(); int count =0; while (true) { int r = rand.nextInt(2); System.out.print(progress[id % progress.length]); if (count % 100 == 0) try { ResultSet rs; rs = s.executeQuery("show variables like 'innodb_locks_unsafe_for_binlog'"); if (rs.next()) System.out.println("innodb_locks_unsafe_for_binlog: "+rs.getString(2)); rs = s.executeQuery("show variables like 'tx_isolation'"); if (rs.next()) System.out.println("isolation: "+rs.getString(2)); conn.commit(); } catch (SQLException e) {} count++; try { switch (r) { case 0: insert(conn,s,rand.nextInt(10)+1,rand.nextInt(10+1)); break; case 1: test(conn,s,rand.nextInt(10)+1,rand.nextInt(10+1)); break; default: throw new Exception("well, that was unexpected"); } } catch (SQLException e) { if ("40001".equals(e.getSQLState())) System.out.println("Deadlock"); else { try { conn.close(); } catch (SQLException ex) {} try { conn = DriverManager.getConnection(connect); conn.setTransactionIsolation(iso); conn.setAutoCommit(false); s = conn.createStatement(); } catch (SQLException ex) { throw ex; } } } Thread.sleep(90+rand.nextInt(20)); } } catch (Exception e) { e.printStackTrace(); } } public synchronized static int nextOID() { return oid++; } public void insert(Connection conn, Statement s, int d, int w) throws SQLException { int o = nextOID(); String sql = "insert into order_table (o_id,o_d_id,o_w_id,o_c_id,o_entry_d,o_ol_cnt,o_all_local) values ("+ o+","+d+","+w+","+id+",'"+new Timestamp(System.currentTimeMillis())+"',"+0+","+0+")"; //System.out.println(sql); s.executeUpdate(sql); conn.commit(); } public void test(Connection conn, Statement s, int d, int w) throws SQLException { List l1 = runQuery(s,d,w); try { Thread.sleep(10); } catch (InterruptedException e) {} List l2 = runQuery(s,d,w); if (!l1.equals(l2)) { System.out.println("Mismatch:"); System.out.println(l1); System.out.println(l2); } conn.commit(); } public List runQuery(Statement s, int d, int w) throws SQLException { ResultSet rs = s.executeQuery("select o_id,o_c_id from order_table "+ "where o_d_id="+d+" and "+ "o_w_id="+w+ " order by o_id desc"); ArrayList l = new ArrayList(); while (rs.next()) { l.add(rs.getInt(1)); } rs.close(); return l; } }