/* * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.bench; import java.io.FileWriter; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import org.h2.store.fs.FileUtils; import org.h2.test.TestBase; import org.h2.util.IOUtils; import org.h2.util.JdbcUtils; /** * Used to compare scalability between the old engine and the new MVStore * engine. Mostly it runs BenchB with various numbers of threads. */ public class TestScalability implements Database.DatabaseTest { /** * Whether data should be collected. */ boolean collect; /** * The flag used to enable or disable trace messages. */ boolean trace; /** * This method is called when executing this sample application. * * @param args the command line parameters */ public static void main(String... args) throws Exception { new TestScalability().test(); } private static Connection getResultConnection() throws SQLException { org.h2.Driver.load(); return DriverManager.getConnection("jdbc:h2:./data/results"); } private static void openResults() throws SQLException { Connection conn = null; Statement stat = null; try { conn = getResultConnection(); stat = conn.createStatement(); stat.execute( "CREATE TABLE IF NOT EXISTS RESULTS(TESTID INT, " + "TEST VARCHAR, UNIT VARCHAR, DBID INT, " + "DB VARCHAR, RESULT VARCHAR)"); } finally { JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(conn); } } private void test() throws Exception { final boolean exit = false; FileUtils.deleteRecursive("data", true); final String out = "benchmark.html"; final int size = 400; ArrayList<Database> dbs = new ArrayList<Database>(); int id = 1; final String h2Url = "jdbc:h2:./data/test;" + "LOCK_TIMEOUT=10000;LOCK_MODE=3"; dbs.add(createDbEntry(id++, "H2", 1, h2Url)); dbs.add(createDbEntry(id++, "H2", 10, h2Url)); dbs.add(createDbEntry(id++, "H2", 20, h2Url)); dbs.add(createDbEntry(id++, "H2", 30, h2Url)); dbs.add(createDbEntry(id++, "H2", 40, h2Url)); dbs.add(createDbEntry(id++, "H2", 50, h2Url)); dbs.add(createDbEntry(id++, "H2", 100, h2Url)); final String mvUrl = "jdbc:h2:./data/mvTest;" + "LOCK_TIMEOUT=10000;MV_STORE=TRUE"; dbs.add(createDbEntry(id++, "MV", 1, mvUrl)); dbs.add(createDbEntry(id++, "MV", 10, mvUrl)); dbs.add(createDbEntry(id++, "MV", 20, mvUrl)); dbs.add(createDbEntry(id++, "MV", 30, mvUrl)); dbs.add(createDbEntry(id++, "MV", 40, mvUrl)); dbs.add(createDbEntry(id++, "MV", 50, mvUrl)); dbs.add(createDbEntry(id++, "MV", 100, mvUrl)); final BenchB test = new BenchB(); testAll(dbs, test, size); collect = false; ArrayList<Object[]> results = dbs.get(0).getResults(); Connection conn = null; PreparedStatement prep = null; Statement stat = null; PrintWriter writer = null; try { openResults(); conn = getResultConnection(); stat = conn.createStatement(); prep = conn.prepareStatement( "INSERT INTO RESULTS(TESTID, " + "TEST, UNIT, DBID, DB, RESULT) VALUES(?, ?, ?, ?, ?, ?)"); for (int i = 0; i < results.size(); i++) { Object[] res = results.get(i); prep.setInt(1, i); prep.setString(2, res[0].toString()); prep.setString(3, res[1].toString()); for (Database db : dbs) { prep.setInt(4, db.getId()); prep.setString(5, db.getName()); Object[] v = db.getResults().get(i); prep.setString(6, v[2].toString()); prep.execute(); } } writer = new PrintWriter(new FileWriter(out)); ResultSet rs = stat.executeQuery( "CALL '<table><tr><th>Test Case</th>" + "<th>Unit</th>' " + "|| SELECT GROUP_CONCAT('<th>' || DB || '</th>' " + "ORDER BY DBID SEPARATOR '') FROM " + "(SELECT DISTINCT DBID, DB FROM RESULTS)" + "|| '</tr>' || CHAR(10) " + "|| SELECT GROUP_CONCAT('<tr><td>' || " + "TEST || '</td><td>' || UNIT || '</td>' || ( " + "SELECT GROUP_CONCAT('<td>' || RESULT || '</td>' " + "ORDER BY DBID SEPARATOR '') FROM RESULTS R2 WHERE " + "R2.TESTID = R1.TESTID) || '</tr>' " + "ORDER BY TESTID SEPARATOR CHAR(10)) FROM " + "(SELECT DISTINCT TESTID, TEST, UNIT FROM RESULTS) R1" + "|| '</table>'"); rs.next(); String result = rs.getString(1); writer.println(result); } finally { JdbcUtils.closeSilently(prep); JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(conn); IOUtils.closeSilently(writer); } if (exit) { System.exit(0); } } private Database createDbEntry(int id, String namePrefix, int threadCount, String url) { Database db = Database.parse(this, id, namePrefix + "(" + threadCount + "threads), org.h2.Driver, " + url + ", sa, sa", threadCount); return db; } private void testAll(ArrayList<Database> dbs, BenchB test, int size) throws Exception { for (int i = 0; i < dbs.size(); i++) { if (i > 0) { Thread.sleep(1000); } // calls garbage collection TestBase.getMemoryUsed(); Database db = dbs.get(i); System.out.println("Testing the performance of " + db.getName()); db.startServer(); Connection conn = db.openNewConnection(); DatabaseMetaData meta = conn.getMetaData(); System.out.println(" " + meta.getDatabaseProductName() + " " + meta.getDatabaseProductVersion()); runDatabase(db, test, 1); runDatabase(db, test, 1); collect = true; runDatabase(db, test, size); conn.close(); db.log("Executed statements", "#", db.getExecutedStatements()); db.log("Total time", "ms", db.getTotalTime()); int statPerSec = (int) (db.getExecutedStatements() * 1000L / db.getTotalTime()); db.log("Statements per second", "#", statPerSec); System.out.println("Statements per second: " + statPerSec); collect = false; db.stopServer(); } } private static void runDatabase(Database db, BenchB bench, int size) throws Exception { bench.init(db, size); bench.setThreadCount(db.getThreadsCount()); bench.runTest(); } /** * Print a message to system out if trace is enabled. * * @param s the message */ @Override public void trace(String s) { if (trace) { System.out.println(s); } } @Override public boolean isCollect() { return collect; } }