From c6c9ddc67473ec3efde0f8e7e1e8bb0e87beeb5b Mon Sep 17 00:00:00 2001 From: "Michael A. McMahon" Date: Tue, 29 Aug 2023 12:35:12 -0700 Subject: [PATCH 1/3] Check for common FJP having zero threads --- .../java/oracle/r2dbc/OracleR2dbcOptions.java | 8 ++++--- .../impl/OracleConnectionFactoryImpl.java | 24 ++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/oracle/r2dbc/OracleR2dbcOptions.java b/src/main/java/oracle/r2dbc/OracleR2dbcOptions.java index 682bf08..a6363c5 100644 --- a/src/main/java/oracle/r2dbc/OracleR2dbcOptions.java +++ b/src/main/java/oracle/r2dbc/OracleR2dbcOptions.java @@ -56,9 +56,11 @@ private OracleR2dbcOptions() {} * ... * .build(); * - * If this option is not configured, then Oracle R2DBC will use - * {@code ForkJoinPool}'s - * {@linkplain ForkJoinPool#commonPool() common pool} by default. + * If this option is not configured, then Oracle R2DBC will + * use the {@linkplain ForkJoinPool#commonPool() common ForkJoinPool} by + * default. However, if the common {@code ForkJoinPool} has a maximum pool + * size that is potentially zero, then a single-threaded {@code Executor} will + * be used by default. */ public static final Option EXECUTOR; diff --git a/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java b/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java index 9019153..1b29eb7 100755 --- a/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java +++ b/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java @@ -102,6 +102,27 @@ */ final class OracleConnectionFactoryImpl implements ConnectionFactory { + /** + *

+ * The default executor when {@link OracleR2dbcOptions#EXECUTOR} is not + * configured. It will use the common {@code ForkJoinPool}, unless it has + * a maximum pool size of 0. See: + * https://github.com/oracle/oracle-r2dbc/issues/129 + *

+ * As of JDK 11, it appears that ForkJoinPool does not expose a + * maximum pool size. {@link ForkJoinPool#getCommonPoolParallelism()} and + * {@link ForkJoinPool#getParallelism()} will return 1 when the maximum pool + * size is 0. For this reason, the conditional below will check for a + * parallelism that is greater than 1, rather than 0. It is noted that + * {@code CompletableFuture} uses the same logic when initializing its + * USE_COMMON_POOL field. + *

+ */ + private static final Executor DEFAULT_EXECUTOR = + ForkJoinPool.getCommonPoolParallelism() > 1 + ? ForkJoinPool.commonPool() + : new ForkJoinPool(1); + /** JDBC data source that this factory uses to open connections */ private final DataSource dataSource; @@ -200,7 +221,7 @@ final class OracleConnectionFactoryImpl implements ConnectionFactory { Object executor = options.getValue(OracleR2dbcOptions.EXECUTOR); if (executor == null) { - this.executor = ForkJoinPool.commonPool(); + this.executor = DEFAULT_EXECUTOR; } else if (executor instanceof Executor) { this.executor = (Executor) executor; @@ -267,4 +288,5 @@ public Publisher create() { public ConnectionFactoryMetadata getMetadata() { return () -> "Oracle Database"; } + } From 53e5f71a2531315fef34c94d035f76d443e80cd5 Mon Sep 17 00:00:00 2001 From: "Michael A. McMahon" Date: Tue, 29 Aug 2023 13:48:00 -0700 Subject: [PATCH 2/3] Reduce concurrency of concurrent tests. --- src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java index eac9a04..59045cf 100644 --- a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java +++ b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java @@ -3222,7 +3222,7 @@ private void verifyConcurrentFetch(Connection connection) { // Create many statements and execute them in parallel. @SuppressWarnings({"unchecked","rawtypes"}) Publisher[] publishers = - new Publisher[Runtime.getRuntime().availableProcessors() * 4]; + new Publisher[Runtime.getRuntime().availableProcessors() * 2]; for (int i = 0; i < publishers.length; i++) { From c801c10847f16f88fc09836e9ac7d1ef6358b292 Mon Sep 17 00:00:00 2001 From: Michael-A-McMahon Date: Wed, 25 Oct 2023 12:09:29 -0700 Subject: [PATCH 3/3] Only check for 0 parallelism property --- .../r2dbc/impl/OracleConnectionFactoryImpl.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java b/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java index 1b29eb7..08b2a5a 100755 --- a/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java +++ b/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java @@ -108,20 +108,13 @@ final class OracleConnectionFactoryImpl implements ConnectionFactory { * configured. It will use the common {@code ForkJoinPool}, unless it has * a maximum pool size of 0. See: * https://github.com/oracle/oracle-r2dbc/issues/129 - *

- * As of JDK 11, it appears that ForkJoinPool does not expose a - * maximum pool size. {@link ForkJoinPool#getCommonPoolParallelism()} and - * {@link ForkJoinPool#getParallelism()} will return 1 when the maximum pool - * size is 0. For this reason, the conditional below will check for a - * parallelism that is greater than 1, rather than 0. It is noted that - * {@code CompletableFuture} uses the same logic when initializing its - * USE_COMMON_POOL field. *

*/ private static final Executor DEFAULT_EXECUTOR = - ForkJoinPool.getCommonPoolParallelism() > 1 - ? ForkJoinPool.commonPool() - : new ForkJoinPool(1); + "0".equals(System.getProperty( + "java.util.concurrent.ForkJoinPool.common.parallelism")) + ? new ForkJoinPool(1) + : ForkJoinPool.commonPool(); /** JDBC data source that this factory uses to open connections */ private final DataSource dataSource;