private int selectInsteadOfUpdatePct = 25;\r
private int rollbackChancePct = 15;\r
private int maxTables = 0;\r
+\r
+ private boolean sequentialIds = false;\r
+ private static Integer currentId = -1;\r
+ \r
+ private boolean sequentialFirsts = false;\r
+ private static Integer currentFirstFirst = 0, currentFirstSecond = 0;\r
\r
private Long randomSeed = null;\r
\r
break;\r
case "-u":\r
case "--update": \r
- currState = 'u';\r
+ doUpdate = false;\r
break;\r
case "-x":\r
case "--delete": \r
- currState = 'x';\r
- break;\r
+ doDelete = false;\r
+ break;\r
case "-l":\r
case "--closeChance": \r
currState = 'l';\r
case "--randomSeed":\r
currState = '?';\r
break;\r
+ case "--sequentialId":\r
+ sequentialIds = true;\r
+ break;\r
+ case "--sequentialFirst": \r
+ sequentialFirsts = true;\r
+ break;\r
default:\r
System.out.println("Didn't understand switch " + arg);\r
}\r
case 'a':\r
additionalDelayBetweenTestsMs = Integer.parseInt(arg);\r
break;\r
- case 'u':\r
- doUpdate = arg.toUpperCase().startsWith("Y");\r
- break;\r
- case 'x':\r
- doDelete = arg.toUpperCase().startsWith("Y");\r
- break;\r
case 'l':\r
connectionCloseChancePct = Integer.parseInt(arg);\r
break;\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
- "-m; --maxCalls: Max number of commits (each may be 1+ updates), default 50\n" + \r
- "-t; --maxTime: Max time in ms test will run, default 60000\n" + \r
- "-d; --minDelay: Min delay between tests in ms, default 1000\n" + \r
- "-a; --addDelay: Max randomized additional delay between tests in ms, default 1000\n" + \r
- "-u; --update: Generate update statements; default Y\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\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
+ "-c; --connection [string]: MDBC connection string, may appear multiple times\n" + \r
+ "-e; --tableName [string]: Table name, may appear multiple times\n" +\r
+ "-n; --name [string]: Last name in persons table, default \"Lastname\"\n" + \r
+ "-b; --baseId [int]: Base ID, default 700\n" + \r
+ "-r; --baseRange [int]: Range of ID, default 50\n" + \r
+ "-m; --maxCalls [int]: Max number of commits (each may be 1+ updates), default 50\n" + \r
+ "-t; --maxTime [int]: Max time in ms test will run, default 60000\n" + \r
+ "-d; --minDelay [int]: Min delay between tests in ms, default 1000\n" + \r
+ "-a; --addDelay [int]: Max randomized additional delay between tests in ms, default 1000\n" + \r
+ "-u; --update: Don't generate update statements; default do\n" + \r
+ "-x; --delete: Don't generate delete statements; default do\n" + \r
+ "-l; --closeChance [int]: Percent chance of closing connection after each commit, default 50\n" +\r
+ "-s; --skipInitialSelect [int]: Percent chance of skipping each initial select in a transaction, default 25\n" +\r
+ "-i; --selectNotUpdate [int]: Percent chance of each action in a transaction being a select instead of an update, default 25\n" +\r
+ "-o; --rollbackChance [int]: Percent chance of rolling back each transaction instead of committing, default 15\n" +\r
+ " --maxTables [int]: Maximum number of tables per transaction, default 0 (no limit)\n" +\r
+ " --randomSeed [long]: Seed for the initial random number generator, default none (generate random random seed)\n" +\r
+ " --sequentialId: Generate sequential IDs instead of random ones (default random)\n" +\r
+ " --sequentialFirst: Generate alphabetically sequential first names (default completely random) \n" +\r
""\r
);\r
\r
this.selectInsteadOfUpdatePct = that.selectInsteadOfUpdatePct;\r
this.rollbackChancePct = that.rollbackChancePct;\r
this.maxTables = that.maxTables;\r
+ this.sequentialIds = that.sequentialIds;\r
+ this.sequentialFirsts = that.sequentialFirsts;\r
}\r
\r
private void setRandomSeed(Long randomSeed) {\r
// doLog("PersonId = " + rs.getInt("personId") + ", lastname = " + rs.getString("lastname") + ", firstname = " + rs.getString("firstname"));\r
Employee emp = new Employee(rs.getInt("personId"), rs.getString("lastname"), rs.getString("firstname"), rs.getString("address"), rs.getString("city"));\r
employeeMap.put(rs.getInt("personId"), emp);\r
+ if (sequentialIds) updateId(rs.getInt("personId"));\r
+ if (sequentialFirsts) updateFirst(rs.getString("firstname"));\r
doLog("Found: " + emp);\r
}\r
querySt.close();\r
insertStmt.close();\r
}\r
\r
- private List<String> chooseTableNames(Random r) {\r
+ private void updateFirst(String firstName) {\r
+ if (firstName==null || firstName.length()<2) return;\r
+ synchronized(currentFirstFirst) {\r
+// return (char)(65+currentFirstFirst) + "" + (char)(97+currentFirstSecond) + generateLetters(r, 4+r.nextInt(4));\r
+ int ff = ((int)firstName.charAt(0))-65;\r
+ int fs = ((int)firstName.charAt(1))-97;\r
+ if (ff>=26 || ff<0 || fs>=26 || fs<0) return;\r
+ if ( (ff>currentFirstFirst) || (ff==currentFirstFirst && fs>currentFirstSecond) ) {\r
+ currentFirstFirst = ff;\r
+ currentFirstSecond = fs;\r
+ doLog("Saw " + firstName + ", updating currentFirstName to " + currentFirstFirst + ", " + currentFirstSecond);\r
+ }\r
+ }\r
+ \r
+ }\r
+\r
+ private void updateId(int id) {\r
+ synchronized(currentId) {\r
+ if (currentId<=id) {\r
+ currentId = id+1;\r
+ doLog ("Saw " + id + ", updating current id");\r
+ }\r
+ }\r
+ }\r
+\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
private String generateInsert(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
String toRet = null;\r
\r
- Integer id = null;\r
- int range = baseIdRange;\r
- while (id==null) {\r
- id = baseId + r.nextInt(range);\r
- if (employeeMap!=null && employeeMap.containsKey(id)) id = null;\r
- if (employeeMap==null) id+=baseIdRange;\r
- range+=(baseIdRange/5);\r
- }\r
- Employee newEmp = new Employee(id, lastName, Character.toUpperCase(randomLetter(r)) + generateLetters(r, 4+r.nextInt(4)), generateLetters(r, 4).toUpperCase(), generateLetters(r, 4).toUpperCase());\r
+ Integer id = generateId(employeeMap, r);\r
+ Employee newEmp = new Employee(id, lastName, generateFirstName(r), generateLetters(r, 4).toUpperCase(), generateLetters(r, 4).toUpperCase());\r
+// Employee newEmp = new Employee(id, lastName, Character.toUpperCase(randomLetter(r)) + generateLetters(r, 4+r.nextInt(4)), generateLetters(r, 4).toUpperCase(), generateLetters(r, 4).toUpperCase());\r
toRet = "insert into " + tableName + " values (" + id + ", '" + newEmp.getLastname() + "', '" + newEmp.getFirstname() + "', '" + newEmp.getAddress() + "', '" + newEmp.getCity() + "')";\r
if (employeeMap!=null) employeeMap.put(id, newEmp);\r
\r
return toRet;\r
}\r
\r
+ private String generateFirstName(Random r) {\r
+ if (sequentialFirsts) {\r
+ synchronized(currentFirstFirst) {\r
+ currentFirstSecond++;\r
+ if (currentFirstSecond==26) {\r
+ currentFirstSecond = 0;\r
+ currentFirstFirst++;\r
+ if (currentFirstFirst==26) currentFirstFirst=0;\r
+ }\r
+ return (char)(65+currentFirstFirst) + "" + (char)(97+currentFirstSecond) + generateLetters(r, 4+r.nextInt(4));\r
+ }\r
+ } else {\r
+ return Character.toUpperCase(randomLetter(r)) + generateLetters(r, 4+r.nextInt(4));\r
+ }\r
+ }\r
+\r
+ private Integer generateId(HashMap<Integer, Employee> employeeMap, Random r) {\r
+ Integer toRet = null;\r
+ if (currentId<0 && baseId>0) currentId = baseId; // setup, only matters if sequentialIds is true\r
+ int range = baseIdRange; // setup, only matters if sequentialIds is false\r
+ while (toRet==null) {\r
+ if (sequentialIds) {\r
+ synchronized(currentId) {\r
+ toRet = currentId++;\r
+ }\r
+ } else {\r
+ toRet = baseId + r.nextInt(range);\r
+ if (employeeMap==null) toRet+=baseIdRange;\r
+ range+=(baseIdRange/5);\r
+ }\r
+ if (employeeMap!=null && employeeMap.containsKey(toRet)) toRet = null;\r
+ }\r
+ return toRet;\r
+ }\r
+\r
private String generateUpdate(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
String toRet = null;\r
\r
Employee toUpd = chooseTarget(employeeMap, r);\r
if (toUpd!=null) {\r
String newFirst = null;\r
- if (toUpd.getFirstname().length()<=3 || r.nextBoolean()) {\r
+ if (sequentialFirsts) {\r
+ newFirst = generateFirstName(r);\r
+ } else if (toUpd.getFirstname().length()<=3 || r.nextBoolean()) {\r
newFirst = toUpd.getFirstname() + randomLetter(r);\r
} else {\r
newFirst = toUpd.getFirstname().substring(0, toUpd.getFirstname().length()-1);\r
}\r
-// toRet = "update " + tableName + " set firstname = '" + newFirst + "' where personid = " + toUpd.getEmpid();\r
toRet = "update " + tableName + " set firstname = '" + newFirst + "' where personid = " + toUpd.getEmpid() + " and lastname = '" + toUpd.getLastname() + "'";\r
toUpd.setFirstname(newFirst);\r
}\r