import java.sql.*;\r
import java.text.SimpleDateFormat;\r
import java.util.ArrayList;\r
+import java.util.Arrays;\r
import java.util.HashMap;\r
import java.util.List;\r
import java.util.Random;\r
private int connectionCloseChancePct = 50;\r
private int skipInitialSelectPct = 25;\r
private int selectInsteadOfUpdatePct = 25;\r
+ private int rollbackChancePct = 15;\r
+ private int maxTables = 0;\r
\r
+ private Long randomSeed = null;\r
+\r
+ private List<String> tableNames = new ArrayList<String>();\r
+ private static final List<String> defaultTableNames = Arrays.asList(new String[] {"persons", "persons2"});\r
+\r
private boolean explainConnection = true;\r
\r
public static class Employee {\r
case "--connection": \r
currState = 'c';\r
break;\r
+ case "-e":\r
+ case "--tableName": \r
+ currState = 'e';\r
+ break;\r
case "-n":\r
case "--name": \r
currState = 'n';\r
case "--selectNotUpdate":\r
currState = 'i';\r
break;\r
+ case "-o":\r
+ case "--rollbackChance":\r
+ currState = 'o';\r
+ break;\r
+ case "--maxTables":\r
+ currState = '@';\r
+ break;\r
+ case "--randomSeed":\r
+ currState = '?';\r
+ break;\r
default:\r
System.out.println("Didn't understand switch " + arg);\r
}\r
} else {\r
try {\r
switch (currState) {\r
- case 'c':\r
- connectionStrings.add(arg);\r
+ case 'c':\r
+ connectionStrings.add(arg);\r
+ break;\r
+ case 'e':\r
+ tableNames.add(arg);\r
break;\r
case 'n':\r
lastName = arg;\r
case 'i': \r
selectInsteadOfUpdatePct = Integer.parseInt(arg);\r
break;\r
+ case 'o':\r
+ rollbackChancePct = Integer.parseInt(arg);\r
+ break;\r
+ case '@':\r
+ maxTables = Integer.parseInt(arg);\r
+ break;\r
+ case '?':\r
+ randomSeed = Long.parseLong(arg);\r
+ break;\r
default:\r
System.out.println("Bad state " + currState + "????");\r
}\r
}\r
}\r
if (connectionStrings.isEmpty()) connectionStrings.add(defaultConnection);\r
+ if (tableNames.isEmpty()) tableNames.addAll(defaultTableNames);\r
}\r
\r
private void showHelp() {\r
System.out.println(\r
"-?; --help: Show help\n" + \r
"-c; --connection: MDBC connection string, may appear multiple times\n" + \r
+ "-e; --tableName: Table name, may appear multiple times\n" +\r
"-n; --name: Last name in persons table, default \"Lastname\"\n" + \r
"-b; --baseId: Base ID, default 700\n" + \r
"-r; --baseRange: Range of ID, default 50\n" + \r
"-x; --delete: Generate delete statements; default Y\n" + \r
"-l; --closeChance: Percent chance of closing connection after each commit, default 50\n" +\r
"-s; --skipInitialSelect: Percent chance of skipping each initial select in a transaction, default 25\n" +\r
- "-i; --selectNotUpdate: Percent chance of each action in a transaction being a select instead of an update, default 25"\r
+ "-i; --selectNotUpdate: Percent chance of each action in a transaction being a select instead of an update, default 25\n" +\r
+ "-o; --rollbackChance: Percent chance of rolling back each transaction instead of committing, default 15\n" +\r
+ " --maxTables: Maximum number of tables per transaction, default 0 (no limit)\n" +\r
+ " --randomSeed: Seed for the initial random number generator, default none\n" +\r
+ ""\r
);\r
\r
}\r
\r
public MdbcTestMultiClient(MdbcTestMultiClient that, int i) {\r
this.connectionString = that.connectionStrings.get(i);\r
+ this.tableNames = that.tableNames;\r
this.threadId = i;\r
\r
this.lastName = that.lastName;\r
this.connectionCloseChancePct = that.connectionCloseChancePct;\r
this.skipInitialSelectPct = that.skipInitialSelectPct;\r
this.selectInsteadOfUpdatePct = that.selectInsteadOfUpdatePct;\r
+ this.rollbackChancePct = that.rollbackChancePct;\r
+ this.maxTables = that.maxTables;\r
+ }\r
+\r
+ private void setRandomSeed(Long randomSeed) {\r
+ this.randomSeed = randomSeed;\r
}\r
- \r
- private static String[] tableNames = {"persons", "persons2"};\r
\r
private void doTest(Connection connection, Random r) throws SQLException {\r
doLog("skipInitialSelectPct = " + skipInitialSelectPct + ", selectInsteadOfUpdatePct = " + selectInsteadOfUpdatePct);\r
HashMap<String, HashMap<Integer, Employee>> employeeMaps = new HashMap<String, HashMap<Integer, Employee>> ();\r
// HashMap<Integer, Employee> employeeMap = new HashMap<Integer, Employee>();\r
\r
- for (String tableName : tableNames) {\r
+ List<String> myTableNames = chooseTableNames(r);\r
+ \r
+ for (String tableName : myTableNames) {\r
if (r.nextInt(100)<skipInitialSelectPct) {\r
doLog("Skipping select");\r
// employeeMap = null;\r
\r
while (firstTry || r.nextBoolean()) {\r
firstTry = false;\r
- String tableName = tableNames[r.nextInt(tableNames.length)];\r
+ String tableName = myTableNames.get(r.nextInt(myTableNames.size()));\r
HashMap<Integer, Employee> employeeMap = employeeMaps.get(tableName);\r
if (r.nextInt(100)<selectInsteadOfUpdatePct) {\r
Statement querySt = connection.createStatement();\r
}\r
}\r
\r
- connection.commit();\r
-\r
+ if (r.nextInt(100)<rollbackChancePct) {\r
+ doLog("Rollback!");\r
+ connection.rollback();\r
+ } else {\r
+ doLog("Commit");\r
+ connection.commit();\r
+ }\r
+ \r
insertStmt.close();\r
}\r
\r
- private void executeUpdateTimed(String sql, Statement insertStmt, boolean swallowException) throws SQLException {\r
+ private List<String> chooseTableNames(Random r) {\r
+ if (maxTables<=0 || maxTables>=tableNames.size()) return tableNames;\r
+ boolean[] useTable = new boolean[tableNames.size()];\r
+ for (int i=0; i<tableNames.size(); i++) useTable[i] = false;\r
+ for (int i=0; i<maxTables; i++) useTable[r.nextInt(tableNames.size())] = true;\r
+ List<String> toRet = new ArrayList<String>();\r
+ for (int i=0; i<tableNames.size(); i++) if (useTable[i]) toRet.add(tableNames.get(i));\r
+ doLog("Selected tables: " + toRet);\r
+ return toRet;\r
+ }\r
+\r
+ private void executeUpdateTimed(String sql, Statement insertStmt, boolean swallowException) throws SQLException {\r
long beforeTime, afterTime;\r
\r
beforeTime = new java.util.Date().getTime();\r
} catch (org.apache.calcite.avatica.AvaticaSqlException e) {\r
if (swallowException) {\r
doLog("Caught exception: " + e);\r
+ e.printStackTrace();\r
} else {\r
throw e;\r
}\r
\r
int calls = 0;\r
long startTime = new java.util.Date().getTime();\r
- Random r = new Random();\r
+ Random r = null;\r
+ if (randomSeed==null) {\r
+ r = new Random();\r
+ doLog("Generated new rng");\r
+ } else {\r
+ r = new Random(randomSeed);\r
+ doLog("Generated new rng with seed " + randomSeed);\r
+ }\r
boolean done = false;\r
\r
while (!done) {\r
\r
if (calls==0) {\r
long initialDelay = 1 + (1000*threadId);\r
+// initialDelay = 1;\r
synchronized(Thread.currentThread()) {\r
doLog("Delaying for " + initialDelay);\r
try {\r
}\r
\r
private void runTests() {\r
+ if (randomSeed==null) {\r
+ randomSeed = new Random().nextLong();\r
+ }\r
+ doLog("Using random seed = " + randomSeed);\r
+ Random seedRandom = new Random(randomSeed);\r
for (int i=0; i<connectionStrings.size(); i++) {\r
MdbcTestMultiClient mt = new MdbcTestMultiClient(this, i);\r
+ mt.setRandomSeed(seedRandom.nextLong());\r
Thread t = new Thread(mt);\r
t.start();\r
}\r