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