diff --git a/CHANGELOG.md b/CHANGELOG.md index 127178bcf..0e6ac6075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,14 @@ ## Change log -### 9.0.2-b2 (12/7/2023 - ) +### 9.0.2 (12/7/2023 - 12/12/2023) * stats: dump virtual threads on high cpu * http: response "connection: keep-alive" header if client sends keep-alive header > to be compatible with http/1.0 client, like ab (apache benchmark) with "-k" * mysql: patched mysql jdbc driver to support virtual thread and gcloud auth - > use "core.framework.mysql:mysql-connector-j:8.2.0-p2" - > for db-migration, pls continue to use "com.mysql:mysql-connector-j:8.2.0@jar", as our patched version may remove outdated features + > use "core.framework.mysql:mysql-connector-j:8.2.0" + > !!! for db-migration, pls continue to use "com.mysql:mysql-connector-j:8.2.0", as our patched version may remove unused features + > refer to https://github.com/neowu/mysql-connector-j ### 9.0.1 (12/01/2023 - 12/7/2023) diff --git a/build.gradle.kts b/build.gradle.kts index 5ac0fb9e1..42dcdffa1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ apply(plugin = "project") subprojects { group = "core.framework" - version = "9.0.2-b2" + version = "9.0.2" repositories { maven { @@ -42,7 +42,7 @@ project("core-ng") { implementation("io.undertow:undertow-core:2.3.10.Final") implementation("org.apache.kafka:kafka-clients:${kafkaVersion}@jar") implementation("org.xerial.snappy:snappy-java:1.1.10.5") // used by kafka message compression - compileOnly("core.framework.mysql:mysql-connector-j:8.2.0-p2") + compileOnly("core.framework.mysql:mysql-connector-j:8.2.0") compileOnly("org.jboss.logging:jboss-logging-annotations:2.2.1.Final") compileOnly("com.github.spotbugs:spotbugs-annotations:4.8.0") testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") diff --git a/core-ng-test/src/test/java/core/framework/test/TestModule.java b/core-ng-test/src/test/java/core/framework/test/TestModule.java index 96fe8c5ef..633332f8c 100644 --- a/core-ng-test/src/test/java/core/framework/test/TestModule.java +++ b/core-ng-test/src/test/java/core/framework/test/TestModule.java @@ -113,6 +113,7 @@ private void configureDB() { db().url("jdbc:mysql://localhost:3306/test"); db().isolationLevel(IsolationLevel.READ_UNCOMMITTED); db().timeout(Duration.ofSeconds(10)); + db().poolSize(5, 5); db().longTransactionThreshold(Duration.ofSeconds(5)); db().repository(TestDBEntity.class); db().repository(TestDBEntityWithJSON.class); diff --git a/core-ng/src/main/java/core/framework/db/CloudAuthProvider.java b/core-ng/src/main/java/core/framework/db/CloudAuthProvider.java index 756b2d062..49b9e1f38 100644 --- a/core-ng/src/main/java/core/framework/db/CloudAuthProvider.java +++ b/core-ng/src/main/java/core/framework/db/CloudAuthProvider.java @@ -8,15 +8,15 @@ public interface CloudAuthProvider { String accessToken(); - class Registry { + class Provider { // used by driver to determine if current connection requires cloud auth, for multiple connections with different auth - public static final String KEY = "core.framework.db.authProvider"; + public static final String CLOUD_AUTH = "core.framework.db.cloudAuth"; // in cloud env, only need one global auth provider private static CloudAuthProvider provider; - public static void register(CloudAuthProvider provider) { - if (Registry.provider != null) throw new Error("provider is registered, provider=" + Registry.provider); - Registry.provider = provider; + public static void set(CloudAuthProvider provider) { + if (Provider.provider != null) throw new Error("provider is set, provider=" + Provider.provider); + Provider.provider = provider; } public static CloudAuthProvider get() { diff --git a/core-ng/src/main/java/core/framework/internal/async/ThreadPools.java b/core-ng/src/main/java/core/framework/internal/async/ThreadPools.java index 10f4cc56b..34e37fab9 100644 --- a/core-ng/src/main/java/core/framework/internal/async/ThreadPools.java +++ b/core-ng/src/main/java/core/framework/internal/async/ThreadPools.java @@ -15,8 +15,10 @@ public final class ThreadPools { // increase parallelism to allow more virtual thread unfriendly tasks to run // refer to https://bugs.mysql.com/bug.php?id=110512 // refer to java.lang.VirtualThread.createDefaultScheduler - int parallelism = Math.max(Runtime.getRuntime().availableProcessors(), 16); - System.setProperty("jdk.virtualThreadScheduler.parallelism", String.valueOf(parallelism)); + if (System.getProperty("jdk.virtualThreadScheduler.parallelism") == null) { + int parallelism = Math.max(Runtime.getRuntime().availableProcessors(), 16); + System.setProperty("jdk.virtualThreadScheduler.parallelism", String.valueOf(parallelism)); + } } public static ExecutorService virtualThreadExecutor(String prefix) { diff --git a/core-ng/src/main/java/core/framework/internal/db/DatabaseImpl.java b/core-ng/src/main/java/core/framework/internal/db/DatabaseImpl.java index 50283607d..eac8c5795 100644 --- a/core-ng/src/main/java/core/framework/internal/db/DatabaseImpl.java +++ b/core-ng/src/main/java/core/framework/internal/db/DatabaseImpl.java @@ -8,7 +8,6 @@ import core.framework.db.Repository; import core.framework.db.Transaction; import core.framework.db.UncheckedSQLException; -import core.framework.internal.db.cloud.GCloudAuthProvider; import core.framework.internal.log.ActionLog; import core.framework.internal.log.LogManager; import core.framework.internal.resource.Pool; @@ -48,11 +47,11 @@ public final class DatabaseImpl implements Database { public String user; public String password; + public CloudAuthProvider authProvider; public IsolationLevel isolationLevel; private String url; private Properties driverProperties; - private CloudAuthProvider authProvider; private Duration timeout; private Driver driver; private Dialect dialect; @@ -133,7 +132,7 @@ Properties driverProperties(String url) { // refer to https://cloud.google.com/sql/docs/mysql/authentication if (authProvider != null) { properties.setProperty(PropertyKey.sslMode.getKeyName(), PropertyDefinitions.SslMode.PREFERRED.name()); - properties.setProperty(CloudAuthProvider.Registry.KEY, "cloud"); + properties.setProperty(CloudAuthProvider.Provider.CLOUD_AUTH, "true"); } else if (index == -1 || url.indexOf("sslMode=", index + 1) == -1) { properties.setProperty(PropertyKey.sslMode.getKeyName(), PropertyDefinitions.SslMode.DISABLED.name()); } @@ -160,17 +159,6 @@ public void timeout(Duration timeout) { pool.checkoutTimeout(timeout); } - public void authProvider(String provider) { - logger.info("use cloud auth provider, provider={}", provider); - if ("gcloud".equals(provider)) { - authProvider = new GCloudAuthProvider(); - // supports multiple db(), mix and match with cloud auth and user/password - if (CloudAuthProvider.Registry.get() == null) CloudAuthProvider.Registry.register(new GCloudAuthProvider()); - } else { - throw new Error("unsupported cloud auth provider, provider=" + provider); - } - } - public void url(String url) { if (!url.startsWith("jdbc:")) throw new Error("jdbc url must start with \"jdbc:\", url=" + url); logger.info("set database connection url, url={}", url); diff --git a/core-ng/src/main/java/core/framework/module/DBConfig.java b/core-ng/src/main/java/core/framework/module/DBConfig.java index 8d18806a8..70df4d3ed 100644 --- a/core-ng/src/main/java/core/framework/module/DBConfig.java +++ b/core-ng/src/main/java/core/framework/module/DBConfig.java @@ -1,9 +1,11 @@ package core.framework.module; +import core.framework.db.CloudAuthProvider; import core.framework.db.Database; import core.framework.db.IsolationLevel; import core.framework.db.Repository; import core.framework.internal.db.DatabaseImpl; +import core.framework.internal.db.cloud.GCloudAuthProvider; import core.framework.internal.module.Config; import core.framework.internal.module.ModuleContext; import core.framework.internal.module.ShutdownHook; @@ -59,7 +61,12 @@ String databaseURL(String url) { public void user(String user) { if ("iam/gcloud".equals(user)) { - database.authProvider("gcloud"); + CloudAuthProvider provider = CloudAuthProvider.Provider.get(); + if (provider == null) { + provider = new GCloudAuthProvider(); + CloudAuthProvider.Provider.set(provider); + } + database.authProvider = provider; context.logManager.maskFields("access_token"); // mask token from IAM http response } else { database.user = user; diff --git a/core-ng/src/test/java/core/framework/internal/db/DatabaseImplTest.java b/core-ng/src/test/java/core/framework/internal/db/DatabaseImplTest.java index 1a1176584..745195b70 100644 --- a/core-ng/src/test/java/core/framework/internal/db/DatabaseImplTest.java +++ b/core-ng/src/test/java/core/framework/internal/db/DatabaseImplTest.java @@ -2,6 +2,7 @@ import core.framework.db.Transaction; import core.framework.db.UncheckedSQLException; +import core.framework.internal.db.cloud.GCloudAuthProvider; import core.framework.internal.log.ActionLog; import core.framework.internal.log.LogLevel; import core.framework.internal.log.LogManager; @@ -236,7 +237,7 @@ void driverProperties() { .doesNotContainKeys("sslMode") .containsEntry("characterEncoding", "utf-8"); - database.authProvider("gcloud"); + database.authProvider = new GCloudAuthProvider(); properties = database.driverProperties("jdbc:mysql://localhost/demo"); assertThat(properties) .containsEntry("sslMode", "PREFERRED");