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