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);
}
}