From bdf518841b40a5090614fe0892ce582e2ff3ea0c Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Tue, 13 Aug 2019 11:05:53 +0200 Subject: [PATCH] #125 - First draft of R2DBC benchmarks. TODOs: - Review interaction with the JDBC auto-configuration - Wait for tcp protocol of H2 to be supported - Wait for Postgres to accept credentialless connections (see [0]) [0] https://github.com/r2dbc/r2dbc-postgresql/issues/125 --- benchmark/relational/pom.xml | 26 +++++ .../data/microbenchmark/r2dbc/Book.java | 43 +++++++ .../microbenchmark/r2dbc/R2dbcBenchmark.java | 105 ++++++++++++++++++ .../r2dbc/R2dbcBookRepository.java | 44 ++++++++ .../microbenchmark/r2dbc/R2dbcFixture.java | 58 ++++++++++ .../application-h2-in-memory.properties | 1 + .../main/resources/application-h2.properties | 5 + .../resources/application-postgres.properties | 3 + .../resources/application-r2dbc.properties | 2 + 9 files changed, 287 insertions(+) create mode 100644 benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/Book.java create mode 100644 benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBenchmark.java create mode 100644 benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBookRepository.java create mode 100644 benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcFixture.java create mode 100644 benchmark/relational/src/main/resources/application-r2dbc.properties diff --git a/benchmark/relational/pom.xml b/benchmark/relational/pom.xml index cdb42af..8d08166 100644 --- a/benchmark/relational/pom.xml +++ b/benchmark/relational/pom.xml @@ -13,6 +13,10 @@ spring-data-benchmark-relational Spring Data Benchmarks - Relational Microbenchmarks + + + 0.1.0.BUILD-SNAPSHOT + @@ -41,6 +45,28 @@ postgresql + + + + org.springframework.boot.experimental + spring-boot-starter-data-r2dbc + ${spring-boot-data-r2dbc.version} + + + + io.r2dbc + r2dbc-h2 + 0.8.0.M8 + + + + io.r2dbc + r2dbc-postgresql + 0.8.0.M8 + + + + org.mockito mockito-core diff --git a/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/Book.java b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/Book.java new file mode 100644 index 0000000..1b5ad1b --- /dev/null +++ b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/Book.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.r2dbc; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.Value; +import lombok.experimental.Wither; + +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.PersistenceConstructor; + +/** + * @author Oliver Drotbohm + */ +@Value +@RequiredArgsConstructor(access = AccessLevel.PACKAGE, onConstructor = @__(@PersistenceConstructor)) +class Book { + + @Wither(AccessLevel.PACKAGE) @Id Long id; + String title; + int pages; + + public Book(String title, int pages) { + + this.id = null; + this.title = title; + this.pages = pages; + } +} diff --git a/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBenchmark.java b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBenchmark.java new file mode 100644 index 0000000..1ea478b --- /dev/null +++ b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBenchmark.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.r2dbc; + +import java.util.function.Function; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.infra.Blackhole; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.microbenchmark.common.AbstractMicrobenchmark; +import org.springframework.data.r2dbc.core.DatabaseClient; + +import io.r2dbc.spi.Row; + +/** + * Benchmark for R2DBC and Spring Data R2DBC + * + * @author Oliver Drotbohm + */ +public class R2dbcBenchmark extends AbstractMicrobenchmark { + + private static final String FIND_ALL_SQL = "SELECT id, title, pages FROM Book"; + private static final String BY_TITLE_SQL = FIND_ALL_SQL + " where title = :title"; + + @Param({ /* "postgres", */ "h2-in-memory" /*, "h2" */ }) + String profile; + + private DatabaseClient operations; + private Function mapper; + + private R2dbcBookRepository repository; + + @Setup + public void setUp() { + + R2dbcFixture fixture = new R2dbcFixture(profile); + + ConfigurableApplicationContext context = fixture.getContext(); + + this.operations = context.getBean(DatabaseClient.class); + this.mapper = row -> new Book(row.get("id", Long.class), row.get("title", String.class), row.get("pages", Integer.class)); + + this.repository = context.getBean(R2dbcBookRepository.class); + } + + @Benchmark + public void findByTitle(Blackhole sink) { + + sink.consume(operations.execute(BY_TITLE_SQL) // + .bind("title", "title0") // + .map(mapper) + .one() // + .block()); + } + + @Benchmark + public void findAll(Blackhole sink) { + + sink.consume(operations.execute(FIND_ALL_SQL) // + .map(mapper) // + .all() // + .collectList() // + .block()); + } + + @Benchmark + public void repositoryFindByTitle(Blackhole sink) { + sink.consume(repository.findByTitle("title0").block()); + } + + @Benchmark + public void repositoryFindTransactionalByTitle(Blackhole sink) { + sink.consume(repository.findTransactionalByTitle("title0").block()); + } + + @Benchmark + public void repositoryFindAll(Blackhole sink) { + sink.consume(repository.findAll().collectList().block()); + } + + public static void main(String[] args) { + + new R2dbcFixture("postgres") // + .getContext() // + .getBean(R2dbcBookRepository.class) // + .findAll() // + .collectList() // + .block(); + } +} diff --git a/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBookRepository.java b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBookRepository.java new file mode 100644 index 0000000..55f8c69 --- /dev/null +++ b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcBookRepository.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.r2dbc; + +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.data.r2dbc.repository.query.Query; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * A repository for {@link Book} instances. + * + * @author Oliver Drotbohm + */ +interface R2dbcBookRepository extends R2dbcRepository { + + static final String BY_TITLE = "SELECT id, title, pages FROM Book where title = :title"; + + @Transactional(propagation = Propagation.NOT_SUPPORTED) + Flux findAll(); + + @Query(BY_TITLE) + Mono findByTitle(String title); + + @Transactional(readOnly = true) + @Query(BY_TITLE) + Mono findTransactionalByTitle(String title); +} diff --git a/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcFixture.java b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcFixture.java new file mode 100644 index 0000000..40eecc2 --- /dev/null +++ b/benchmark/relational/src/main/java/org/springframework/data/microbenchmark/r2dbc/R2dbcFixture.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.microbenchmark.r2dbc; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.r2dbc.R2dbcProperties; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.data.microbenchmark.FixtureUtils; +import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; + +import io.r2dbc.spi.ConnectionFactory; +import lombok.Getter; + +/** + * Test fixture for JDBC and Spring Data JDBC benchmarks. + * + * @author Oliver Drotbohm + */ +public class R2dbcFixture { + + private final @Getter ConfigurableApplicationContext context; + + public R2dbcFixture(String database) { + + this.context = FixtureUtils.createContext(R2dbcApplication.class, "r2dbc", database); + + R2dbcProperties properties = context.getBean(R2dbcProperties.class); + String platform = properties.getPlatform(); + + Resource schema = new ClassPathResource(String.format("schema-%s.sql", platform)); + Resource data = new ClassPathResource(String.format("data-%s.sql", platform)); + + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(schema, data); + populator.execute(context.getBean(ConnectionFactory.class)).block(); + } + + + @SpringBootApplication (exclude = { + DataSourceAutoConfiguration.class + }) + static class R2dbcApplication {} +} diff --git a/benchmark/relational/src/main/resources/application-h2-in-memory.properties b/benchmark/relational/src/main/resources/application-h2-in-memory.properties index 7eecee5..09e4bd6 100644 --- a/benchmark/relational/src/main/resources/application-h2-in-memory.properties +++ b/benchmark/relational/src/main/resources/application-h2-in-memory.properties @@ -1,2 +1,3 @@ spring.datasource.platform=h2 +spring.r2dbc.platform=h2 diff --git a/benchmark/relational/src/main/resources/application-h2.properties b/benchmark/relational/src/main/resources/application-h2.properties index 1e4cfa4..f977da2 100644 --- a/benchmark/relational/src/main/resources/application-h2.properties +++ b/benchmark/relational/src/main/resources/application-h2.properties @@ -4,3 +4,8 @@ spring.datasource.password= spring.datasource.platform=h2 spring.datasource.initialization-mode=always +spring.r2dbc.url=r2dbc:h2:tcp://localhost:9092/~/benchmark +spring.r2dbc.username=sa +spring.r2dbc.password= +spring.r2dbc.platform=h2 +spring.r2dbc.initialization-mode=always diff --git a/benchmark/relational/src/main/resources/application-postgres.properties b/benchmark/relational/src/main/resources/application-postgres.properties index afd1d52..db931a0 100644 --- a/benchmark/relational/src/main/resources/application-postgres.properties +++ b/benchmark/relational/src/main/resources/application-postgres.properties @@ -2,3 +2,6 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/benchmark spring.datasource.platform=postgres spring.datasource.initialization-mode=always +spring.r2dbc.url=r2dbc:postgresql://localhost:5432/benchmark +spring.r2dbc.platform=postgres +spring.r2dbc.initialization-mode=always \ No newline at end of file diff --git a/benchmark/relational/src/main/resources/application-r2dbc.properties b/benchmark/relational/src/main/resources/application-r2dbc.properties new file mode 100644 index 0000000..9273bdb --- /dev/null +++ b/benchmark/relational/src/main/resources/application-r2dbc.properties @@ -0,0 +1,2 @@ +spring.data.jpa.repositories.enabled=false +spring.data.jdbc.repositories.enabled=false