diff --git a/pom.xml b/pom.xml index 5e248e87..dc202f93 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,18 @@ 1.19.0 test + + org.openjdk.jmh + jmh-core + 1.37 + test + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + test + @@ -221,8 +233,29 @@ + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + benchmark-stateless-small + exec + + test + java + + -classpath + + org.openjdk.jmh.Main + + net.starschema.clouddb.jdbc.StatelessSmallQueryBenchmark + + + + + + - - diff --git a/src/test/java/net/starschema/clouddb/jdbc/ConnectionFromResources.java b/src/test/java/net/starschema/clouddb/jdbc/ConnectionFromResources.java new file mode 100644 index 00000000..ad6120d3 --- /dev/null +++ b/src/test/java/net/starschema/clouddb/jdbc/ConnectionFromResources.java @@ -0,0 +1,44 @@ +package net.starschema.clouddb.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Utility class to enable BigQuery connections from properties resources. */ +public class ConnectionFromResources { + private static final Logger logger = LoggerFactory.getLogger(ConnectionFromResources.class); + + /** + * Connect to a BigQuery project as described in a properties file + * + * @param propertiesFilePath the path to the properties in file in src/test/resources + * @param extraUrl extra URL arguments to add; must start with & + * @return A {@link BQConnection} connected to the given database + * @throws IOException if the properties file cannot be read + * @throws SQLException if the configuration can't connect to BigQuery + */ + public static BQConnection connect(String propertiesFilePath, String extraUrl) + throws IOException, SQLException { + final Properties properties = new Properties(); + final ClassLoader loader = ConnectionFromResources.class.getClassLoader(); + try (InputStream stream = loader.getResourceAsStream(propertiesFilePath)) { + properties.load(stream); + } + final StringBuilder jdcbUrlBuilder = + new StringBuilder(BQSupportFuncts.constructUrlFromPropertiesFile(properties)); + if (extraUrl != null) { + jdcbUrlBuilder.append(extraUrl); + } + final String jdbcUrl = jdcbUrlBuilder.toString(); + + final Connection connection = DriverManager.getConnection(jdbcUrl, properties); + final BQConnection bqConnection = (BQConnection) connection; + logger.info("Created connection from {} to {}", propertiesFilePath, bqConnection.getURLPART()); + return bqConnection; + } +} diff --git a/src/test/java/net/starschema/clouddb/jdbc/StatelessSmallQueryBenchmark.java b/src/test/java/net/starschema/clouddb/jdbc/StatelessSmallQueryBenchmark.java new file mode 100644 index 00000000..d07c07f3 --- /dev/null +++ b/src/test/java/net/starschema/clouddb/jdbc/StatelessSmallQueryBenchmark.java @@ -0,0 +1,84 @@ +package net.starschema.clouddb.jdbc; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import org.assertj.core.api.Assertions; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; + +/** + * Performance microbenchmark for stateless queries. This uses the example query from {@link + * StatelessQuery}, same as the tests. + * + *

Run with mvn exec:exec@benchmark-stateless - note that mvn install must have been run at least + * once before. + */ +@Fork(1) +@Threads(10) +@BenchmarkMode(Mode.Throughput) +public class StatelessSmallQueryBenchmark { + private static final String CONNECTION_PROPERTIES = "installedaccount1.properties"; + + @State(Scope.Thread) + public static class RequiredJob { + private BQConnection connection; + + @Setup(Level.Trial) + public void connect() throws SQLException, IOException { + connection = ConnectionFromResources.connect(CONNECTION_PROPERTIES, null); + } + + @TearDown + public void disconnect() throws SQLException { + connection.close(); + } + } + + @State(Scope.Thread) + public static class OptionalJob { + private BQConnection connection; + + @Setup(Level.Trial) + public void connect() throws SQLException, IOException { + connection = + ConnectionFromResources.connect( + CONNECTION_PROPERTIES, "&jobcreationmode=JOB_CREATION_OPTIONAL"); + } + + @TearDown + public void disconnect() throws SQLException { + connection.close(); + } + } + + private String[][] benchmarkSmallQuery(final Connection connection) throws SQLException { + final Statement statement = connection.createStatement(); + final ResultSet results = statement.executeQuery(StatelessQuery.exampleQuery()); + final String[][] rows = BQSupportMethods.GetQueryResult(results); + Assertions.assertThat(rows).isEqualTo(StatelessQuery.exampleValues()); + return rows; + } + + @Benchmark + public String[][] benchmarkSmallQueryRequiredJob(final RequiredJob requiredJob) + throws SQLException { + return benchmarkSmallQuery(requiredJob.connection); + } + + @Benchmark + public String[][] benchmarkSmallQueryOptionalJob(final OptionalJob optionalJob) + throws SQLException { + return benchmarkSmallQuery(optionalJob.connection); + } +}