package org.prevayler.demos.scalability;
import org.prevayler.demos.scalability.prevayler.*;
import org.prevayler.demos.scalability.jdbc.*;
import org.prevayler.foundation.serialization.JavaSerializer;
import java.io.*;
import java.util.*;
public class Main {
static private final Properties properties=new Properties();
static public void main( String[] args){
out("\n=============================================================");
out(" Prevayler vs JDBC Scalability Tests ");
out("=============================================================\n");
out("If you have any trouble running the tests, just write to");
out("prevayler-scalability@lists.sourceforge.net and we will be glad to help.\n");
try {
out("Reading the properties file:\n" + propertiesFile().getAbsolutePath());
out("You can edit this file to configure the tests for the next run.\n");
properties.load(new FileInputStream(propertiesFile()));
if (isPrevaylerQueryChosen()) runPrevaylerQuery();
if (isPrevaylerTransactionChosen()) runPrevaylerTransaction();
if (isJdbcQueryChosen()) runJdbcQuery();
if (isJdbcTransactionChosen()) runJdbcTransaction();
out("\n\n\nFor better results, edit the properties file:");
out(propertiesFile().getAbsolutePath());
out("\nYou can publish your best results by mail to:");
out("prevayler-scalability@lists.sourceforge.net. Please include info about your");
out("processors (quantity, type, speed), compiler, VM, operating system and DBMS.");
out("");
out("Scalability test results are published on www.prevayler.org.");
out("See you there.\n");
out("Klaus Wuestefeld and Daniel Santos.\n\n");
}
catch ( Exception ex) {
ex.printStackTrace();
}
catch ( OutOfMemoryError err) {
ScalabilityTestRun.outOfMemory();
}
}
static private void runPrevaylerQuery() throws Exception {
new QueryTestRun(new PrevaylerQuerySubject(),numberOfObjects(),prevaylerQueryThreadsMin(),prevaylerQueryThreadsMax());
}
static private void runPrevaylerTransaction() throws Exception {
PrevaylerTransactionSubject subject=new PrevaylerTransactionSubject(prevaylerTransactionLogDirectory(),prevaylerJournalSerializer());
new TransactionTestRun(subject,numberOfObjects(),prevaylerTransactionThreadsMin(),prevaylerTransactionThreadsMax());
if (isPrevaylerTransactionConsistencyChecked()) {
out("Checking transaction log consistency.");
if (!subject.isConsistent()) throw new RuntimeException("Transaction log consistency check failed.");
out("Transaction log OK.\n");
}
}
static private void runJdbcQuery(){
new QueryTestRun(new JDBCQuerySubject(jdbcDriverClassName(),jdbcConnectionURL(),jdbcUser(),jdbcPassword()),numberOfObjects(),jdbcQueryThreadsMin(),jdbcQueryThreadsMax());
}
static private void runJdbcTransaction(){
new TransactionTestRun(new JDBCTransactionSubject(jdbcDriverClassName(),jdbcConnectionURL(),jdbcUser(),jdbcPassword()),numberOfObjects(),jdbcTransactionThreadsMin(),jdbcTransactionThreadsMax());
}
static private File propertiesFile() throws IOException {
File result=new File("ScalabilityTest.properties");
if (!result.exists()) {
out("Creating the properties file.");
createPropertiesFile(result);
}
return result;
}
static private void createPropertiesFile( File file) throws IOException {
PrintStream stream=new PrintStream(new FileOutputStream(file));
stream.println("###########################################################\n" + "# #\n" + "# PREVAYLER VS JDBC SCALABILITY TEST PROPERTIES #\n"+ "# #\n"+ "###########################################################\n"+ "\n"+ "NumberOfObjects = ONE_HUNDRED_THOUSAND\n"+ "# NumberOfObjects = ONE_MILLION\n"+ "# NumberOfObjects = TEN_MILLION\n"+ "# NumberOfObjects = TWENTY_MILLION\n"+ "#\n"+ "# The results are only valid if both Prevayler and the\n"+ "# database can run the tests without paging memory to disk.\n"+ "#\n"+ "# Running the tests with one hundred thousand objects\n"+ "# (default option) requires approx. 128MB free RAM.\n"+ "# The VM must be started with a sufficient maximum heap\n"+ "# size or you will get an OutOfMemoryError.\n"+ "#\n"+ "# Example for Linux and Windows: java -Xmx128000000 ...\n"+ "#\n"+ "# (This can be set with the scalability.jvmarg property\n"+ "# in build.properties; see sample.build.properties for\n"+ "# examples.)\n"+ "#\n"+ "# Running the tests with one million objects requires\n"+ "# approx. 940MB free RAM.\n"+ "# Running the tests with ten million objects requires\n"+ "# approx. 9.4GB free RAM and a 64bit VM.\n"+ "#\n"+ "# IMPORTANT: Remember to shutdown all other non-vital\n"+ "# processes before running the tests. Even the database\n"+ "# process should be down while running the Prevayler tests\n"+ "# that do not use it.\n"+ "\n"+ "\n"+ "###########################################################\n"+ "# PREVAYLER QUERY TEST\n"+ "\n"+ "RunPrevaylerQueryTest = YES\n"+ "# RunPrevaylerQueryTest = NO\n"+ "\n"+ "PrevaylerQueryThreadsMinimum = 1\n"+ "PrevaylerQueryThreadsMaximum = 5\n"+ "# More threads can produce better results on\n"+ "# multi-processor machines.\n"+ "\n"+ "\n"+ "###########################################################\n"+ "# PREVAYLER TRANSACTION TEST\n"+ "\n"+ "RunPrevaylerTransactionTest = YES\n"+ "# RunPrevaylerTransactionTest = NO\n"+ "\n"+ "PrevaylerTransactionThreadsMinimum = 1\n"+ "PrevaylerTransactionThreadsMaximum = 5\n"+ "#\n"+ "# More threads can produce better results on machines with\n"+ "# multiple disks.\n"+ "\n"+ "TransactionTestCheckConsistency = YES\n"+ "# TransactionTestCheckConsistency = NO\n"+ "#\n"+ "# Verifies the integrity of the journal files produced in\n"+ "# your particular environment.\n"+ "\n"+ "TransactionLogDirectory = TransactionTest\n"+ "#\n"+ "# The full path name can be used. Example for Windows:\n"+ "# TransactionLogDirectory1 = c:\\\\temp\\\\TransactionTest\n"+ "# The back-slash (\\) is the escape character so you must\n"+ "# use two back-slashes (\\\\).\n"+ "\n"+ "PrevaylerJournalSerializer = " + JavaSerializer.class.getName() + "\n"+ "\n"+ "\n"+ "###########################################################\n"+ "# JDBC QUERY TEST\n"+ "\n"+ "RunJdbcQueryTest = NO\n"+ "# RunJdbcQueryTest = YES\n"+ "\n"+ "JdbcQueryThreadsMinimum = 1\n"+ "JdbcQueryThreadsMaximum = 5\n"+ "# More threads can produce better results on some machines.\n"+ "\n"+ "\n"+ "###########################################################\n"+ "# JDBC TRANSACTION TEST\n"+ "\n"+ "RunJdbcTransactionTest = NO\n"+ "# RunJdbcTransactionTest = YES\n"+ "\n"+ "JdbcTransactionThreadsMinimum = 1\n"+ "JdbcTransactionThreadsMaximum = 5\n"+ "# More threads can produce better results on some machines.\n"+ "\n"+ "\n"+ "###########################################################\n"+ "# JDBC CONNECTION\n"+ "# (necessary to run the JDBC tests)\n"+ "\n"+ "JdbcDriverClassName =\n"+ "JdbcConnectionURL =\n"+ "JdbcUser =\n"+ "JdbcPassword =\n"+ "# These two tables are necessary for the JDBC tests:\n"+ "# QUERY_TEST and TRANSACTION_TEST.\n"+ "# Both tables have the same column structure:\n"+ "# ID DECIMAL,\n"+ "# NAME VARCHAR2(8),\n"+ "# STRING1 VARCHAR2(1000),\n"+ "# BIGDECIMAL1 DECIMAL,\n"+ "# BIGDECIMAL2 DECIMAL,\n"+ "# DATE1 DATE,\n"+ "# DATE2 DATE.\n"+ "\n"+ "# IMPORTANT: For best results, create indices on the\n"+ "# QUERY_TEST.NAME and TRANSACTION_TEST.ID columns.\n"+ "# Do not create indices on any other column.\n");
}
static private int numberOfObjects(){
String property=property("NumberOfObjects");
if ("ONE_HUNDRED_THOUSAND".equals(property)) return 100000;
if ("ONE_MILLION".equals(property)) return 1000000;
if ("TEN_MILLION".equals(property)) return 10000000;
if ("TWENTY_MILLION".equals(property)) return 20000000;
throw new RuntimeException("NumberOfObjects property must be equal to ONE_HUNDRED_THOUSAND, ONE_MILLION, TEN_MILLION or TWENTY_MILLION.");
}
static private boolean isPrevaylerQueryChosen(){
return booleanProperty("RunPrevaylerQueryTest");
}
static private int prevaylerQueryThreadsMin(){
return intProperty("PrevaylerQueryThreadsMinimum");
}
static private int prevaylerQueryThreadsMax(){
return intProperty("PrevaylerQueryThreadsMaximum");
}
static private boolean isPrevaylerTransactionChosen(){
return booleanProperty("RunPrevaylerTransactionTest");
}
static private int prevaylerTransactionThreadsMin(){
return intProperty("PrevaylerTransactionThreadsMinimum");
}
static private int prevaylerTransactionThreadsMax(){
return intProperty("PrevaylerTransactionThreadsMaximum");
}
static private boolean isPrevaylerTransactionConsistencyChecked(){
return booleanProperty("TransactionTestCheckConsistency");
}
static private String prevaylerTransactionLogDirectory(){
String result=property("TransactionLogDirectory");
out("\n\nPrevayler TransactionLog Directory: " + result);
return result;
}
static private String prevaylerJournalSerializer(){
String result=properties.getProperty("PrevaylerJournalSerializer");
if (result == null) result=JavaSerializer.class.getName();
out("\n\nPrevayler Journal Serializer: " + result);
return result;
}
static private boolean isJdbcQueryChosen(){
return booleanProperty("RunJdbcQueryTest");
}
static private int jdbcQueryThreadsMin(){
return intProperty("JdbcQueryThreadsMinimum");
}
static private int jdbcQueryThreadsMax(){
return intProperty("JdbcQueryThreadsMaximum");
}
static private boolean isJdbcTransactionChosen(){
return booleanProperty("RunJdbcTransactionTest");
}
static private int jdbcTransactionThreadsMin(){
return intProperty("JdbcTransactionThreadsMinimum");
}
static private int jdbcTransactionThreadsMax(){
return intProperty("JdbcTransactionThreadsMaximum");
}
static private String jdbcDriverClassName(){
return property("JdbcDriverClassName");
}
static private String jdbcConnectionURL(){
return property("JdbcConnectionURL");
}
static private String jdbcUser(){
return property("JdbcUser");
}
static private String jdbcPassword(){
return property("JdbcPassword");
}
static private String property( String name){
String result=properties.getProperty(name);
if (result == null) throw new RuntimeException("Property " + name + " not found.");
return result;
}
static private int intProperty( String name){
try {
return Integer.valueOf(property(name)).intValue();
}
catch ( NumberFormatException nfx) {
out("NumberFormatException reading property " + name);
throw nfx;
}
}
static private boolean booleanProperty( String name){
boolean result="yes".equalsIgnoreCase(property(name));
if (result) return true;
out("\n\n\n" + name + " property is set to "+ property(name)+ ".");
out("This test will be skipped (see properties file).");
return false;
}
static private void out( Object message){
System.out.println(message);
}
}