Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a MySQL JDBC driver extension #4067

Merged
merged 2 commits into from Sep 24, 2019

Conversation

machi1990
Copy link
Member

fixes #2323

/ cc @Sanne @gsmet

@machi1990 machi1990 requested review from gsmet and Sanne and removed request for gsmet September 17, 2019 17:48
}

@BuildStep
void registerExceptionsForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed an upstream PR mysql/mysql-connector-j#43 to reduce some of these. The PR has been moved in the internal queue mysql/mysql-connector-j#43 (comment), hope to see it merged.

extensions/jdbc/pom.xml Outdated Show resolved Hide resolved
integration-tests/jpa-mysqldb/README.md Outdated Show resolved Hide resolved
integration-tests/jpa-mysqldb/README.md Outdated Show resolved Hide resolved
integration-tests/jpa-mysqldb/pom.xml Outdated Show resolved Hide resolved
Copy link
Member

@Sanne Sanne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @machi1990 that's awesome progress, thanks a lot!

I made some minor remarks in various comments - please have a look.

Most importantly, I tried to run it in native but couldn't correctly connect to the database. It's a bit late now so I didn't investigate yet - I will continue with that tomorrow, but could you check in the meantime that the integration test worked fine for you even in native mode?

Thanks!

@Sanne
Copy link
Member

Sanne commented Sep 18, 2019

This seems to be the main problem:

Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:1000)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:817)
	at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:447)
	at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237)
	at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)
	at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:200)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:357)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:346)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:64)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: java.lang.NullPointerException
	at java.util.Properties$LineReader.readLine(Properties.java:434)
	at java.util.Properties.load0(Properties.java:353)
	at java.util.Properties.load(Properties.java:341)
	at com.mysql.cj.util.TimeUtil.loadTimeZoneMappings(TimeUtil.java:226)
	at com.mysql.cj.util.TimeUtil.getCanonicalTimezone(TimeUtil.java:123)
	at com.mysql.cj.protocol.a.NativeProtocol.configureTimezone(NativeProtocol.java:2139)
	at com.mysql.cj.protocol.a.NativeProtocol.initServerSession(NativeProtocol.java:2163)
	at com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer(ConnectionImpl.java:1301)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:958)
	... 14 more

Also, less cricital but I had to run the mysql docker image manually as the wait conditions for docker-maven-plugin aren't working on Linux either.

@machi1990
Copy link
Member Author

Hi @machi1990 that's awesome progress, thanks a lot!

I made some minor remarks in various comments - please have a look.

@Sanne thanks for the review. I have taken into account your feedback.

Most importantly, I tried to run it in native but couldn't correctly connect to the database. It's a bit late now so I didn't investigate yet - I will continue with that tomorrow, but could you check in the meantime that the integration test worked fine for you even in native mode?

Thanks!

This seems to be the main problem:

Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:1000)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:817)
	at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:447)
	at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237)
	at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)
	at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:200)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:357)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:346)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:64)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: java.lang.NullPointerException
	at java.util.Properties$LineReader.readLine(Properties.java:434)
	at java.util.Properties.load0(Properties.java:353)
	at java.util.Properties.load(Properties.java:341)
	at com.mysql.cj.util.TimeUtil.loadTimeZoneMappings(TimeUtil.java:226)
	at com.mysql.cj.util.TimeUtil.getCanonicalTimezone(TimeUtil.java:123)
	at com.mysql.cj.protocol.a.NativeProtocol.configureTimezone(NativeProtocol.java:2139)
	at com.mysql.cj.protocol.a.NativeProtocol.initServerSession(NativeProtocol.java:2163)
	at com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer(ConnectionImpl.java:1301)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:958)
	... 14 more

I was able to run the integration test natively with the timezone property set on my connection url that's why I missed this error. I'll take a look later today. Thanks for spotting this.

Also, less cricital but I had to run the mysql docker image manually as the wait conditions for docker-maven-plugin aren't working on Linux either.

Yeah, I had intermittent problems too and decided to run the docker image manually too (on a separate terminal) and do my tests.

@machi1990
Copy link
Member Author

This seems to be the main problem:

Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:1000)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:817)
	at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:447)
	at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237)
	at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)
	at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:200)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:357)
	at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:346)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:64)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: java.lang.NullPointerException
	at java.util.Properties$LineReader.readLine(Properties.java:434)
	at java.util.Properties.load0(Properties.java:353)
	at java.util.Properties.load(Properties.java:341)
	at com.mysql.cj.util.TimeUtil.loadTimeZoneMappings(TimeUtil.java:226)
	at com.mysql.cj.util.TimeUtil.getCanonicalTimezone(TimeUtil.java:123)
	at com.mysql.cj.protocol.a.NativeProtocol.configureTimezone(NativeProtocol.java:2139)
	at com.mysql.cj.protocol.a.NativeProtocol.initServerSession(NativeProtocol.java:2163)
	at com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer(ConnectionImpl.java:1301)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:958)
	... 14 more

Also, less cricital but I had to run the mysql docker image manually as the wait conditions for docker-maven-plugin aren't working on Linux either.

@Sanne Seems like this resource /com/mysql/cj/util/TimeZoneMapping.properties was missing from the native image.

To solve this, I used substitution to read the resource during build time and substitute the method that required it after trying producing a SubstrateResourceBuildItem and SubstrateResourceBundleBuildItem to solve the issue without success. WDYT?

@gsmet
Copy link
Member

gsmet commented Sep 19, 2019

How do they load the properties? I would have expected a SubstrateResourceBuildItem to work OK.

@machi1990
Copy link
Member Author

How do they load the properties? I would have expected a SubstrateResourceBuildItem to work OK.

With this piece of code

TimeUtil.class.getResourceAsStream("/com/mysql/cj/util/TimeZoneMapping.properties");

the file TimeZoneMapping.properties is in the package com.mysql.cj.util

@Sanne
Copy link
Member

Sanne commented Sep 19, 2019

I guess there's a little performance benefit in the approach you took as you pre-parse the stream.
But is it worth it? Are there other reasons to not use a simple SubstrateResourceBuildItem ?

If you want to keep the current approach, maybe it;s worth doing one more step and also run the iteration on TimeZone.getAvailableIDs() on the properties before they are recorded?

@machi1990
Copy link
Member Author

I guess there's a little performance benefit in the approach you took as you pre-parse the stream.
But is it worth it? Are there other reasons to not use a simple SubstrateResourceBuildItem ?

SubstrateResourceBuildItem did not work, maybe I did something wrong. Also +1 with perf benefit.

If you want to keep the current approach, maybe it;s worth doing one more step and also run the iteration on TimeZone.getAvailableIDs() on the properties before they are recorded?

+1. I'll do this.

@Sanne
Copy link
Member

Sanne commented Sep 19, 2019

hi @machi1990 , could you also rebase and test it on the rebased version please?

I'm afraid the tests need some additional work after recent merges to master, as the servlet API is no longer available by default to the JPAFunctionalityTestEndpoint

@gsmet
Copy link
Member

gsmet commented Sep 19, 2019 via email

@machi1990
Copy link
Member Author

If possible, I would avoid fiddling with substitutions if we can get SubstrateResourceBuildItem to work. I don't think the potential perf benefit is worth the maintenance burden. How did you register the resource? Maybe it's about the path not being right?

I tried producing a new SubstrateResourceBuildItem("/com/mysql/cj/util/TimeZoneMapping.properties") build item.

@gsmet
Copy link
Member

gsmet commented Sep 19, 2019

I don't think the initial / would help. I'm also not sure if you need a .* at the beginning i.e. if the path is relative or absolute.

You can add -H:Log=registerResource to your native image build to have a bit more info about what's going on.

@machi1990 machi1990 force-pushed the jdbc-mysql-extension branch 6 times, most recently from 01743ce to 1951e36 Compare September 20, 2019 14:35
@machi1990
Copy link
Member Author

Hmm this test failure https://dev.azure.com/quarkus-ci/quarkus/_build/results?buildId=8111&view=logs

No LastRequestResponse on exception HttpRequestException: An error occurred while sending the request. System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.CurlException: Couldn't connect to server
   at System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
   at System.Net.Http.CurlHandler.MultiAgent.FinishRequest(StrongToWeakReference`1 easyWrapper, CURLcode messageResult)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.VisualStudio.Services.Common.TaskCancellationExtensions.EnforceCancellation[TResult](Task`1 task, CancellationToken cancellationToken, Func`1 makeMessage, String file, String member, Int32 line)
   at Microsoft.VisualStudio.Services.BlobStore.WebApi.DedupStoreHttpClient.<>c__DisplayClass56_0.<<GetRedirectResponseAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.VisualStudio.Services.Content.Common.AsyncHttpRetryHelper`1.InvokeAsync(CancellationToken cancellationToken)
Information, Downloaded 44.4 MB out of 714.8 MB (6%).

seems unrelated. I forced pushed to re-launch the build.

Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @machi1990 ,

Very nice work as usual. I added a few questions and a few suggestions. Could you have a look?

As for CI, I don't know if we could support MySQL testing at least for JVM Linux. It would be simple if we don't already test MariaDB :).

As for the suggestion for native and initializing the class at runtime, I think it's worth a try. It really looks like a class that should be initialized at runtime and it should solve the threading issue. Or maybe not if we end up hitting a GraalVM bug but, in any case, it seems like the direction we should follow.

Feel free to ping me on Zulip if you want to chat about it!

modules:
- jpa-mysql
name: jpa_mysql
mysql: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would have made it part of the job below, which has only 2 tasks right now (jpa and jpa-postgresql).

There wouldn't be any port conflict so I think we are relatively safe.

ci-templates/native-build-steps.yaml Show resolved Hide resolved
@machi1990
Copy link
Member Author

Hi @machi1990 ,

Very nice work as usual. I added a few questions and a few suggestions. Could you have a look?

As for CI, I don't know if we could support MySQL testing at least for JVM Linux. It would be simple if we don't already test MariaDB :).

Done.

As for the suggestion for native and initializing the class at runtime, I think it's worth a try. It really looks like a class that should be initialized at runtime and it should solve the threading issue. Or maybe not if we end up hitting a GraalVM bug but, in any case, it seems like the direction we should follow.

Feel free to ping me on Zulip if you want to chat about it!

Thanks Guillaume for your availability yesterday. Additional comments added for the AbandonedConnectionCleanupThread substitution.

@gsmet
Copy link
Member

gsmet commented Sep 24, 2019

@Sanne I think we're all good now. As you requested changes, I let you check them and merge if you think it's OK.

Thanks @machi1990 , great work.

@Sanne
Copy link
Member

Sanne commented Sep 24, 2019

Tested it all once more locally. Awesome, great job!

@Sanne
Copy link
Member

Sanne commented Sep 24, 2019

@gsmet I see it's marked for milestone 0.24 rather than 0.23. Does it mean I should hold to merge?

Or feel free to merge.. thanks!

@machi1990
Copy link
Member Author

@gsmet @Sanne great. Thanks for your helpful tips and reviews on this one.

@gsmet
Copy link
Member

gsmet commented Sep 24, 2019

master is 0.24.0 right now, we have a branch for 0.23 release. Things will be easier tomorrow hopefully.

Merging!

@gsmet gsmet merged commit 3a1d51b into quarkusio:master Sep 24, 2019
@machi1990 machi1990 deleted the jdbc-mysql-extension branch September 24, 2019 13:06
@gsmet gsmet added backport? and removed backport? labels Sep 24, 2019
@gsmet gsmet modified the milestones: 0.24.0, 0.23.0 Sep 24, 2019
@gsmet gsmet changed the title add support for MySQL Add a MySQL JDBC driver extension Sep 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Quarkus Support for MySQL
3 participants