xerial / sqlite-jdbc

SQLite JDBC Driver
Apache License 2.0
2.84k stars 619 forks source link

Support the Foreign API from project Panama #717

Open boulder-on opened 2 years ago

boulder-on commented 2 years ago

I've been playing with the Foreign API - the replacement for JNI that's been incubating since Java 14. I have managed to hack a version of the sqlite-jdbc code to use the Foreign API directly against the sqlite3 library without the need for any extra C code. The code I have is only capable of returning Strings, ints and doubles form a query.

The test I ran was

In my test, the Foreign API is about 2x faster than the existing JNI implementation. (mean of 44ms vs 23ms to retrieve all rows and columns).

My experience with the Foreign API is that when passing primitive values it's noticeably faster than JNI. When passing arrays of data the Foreign API is faster than JNI, but the gap is smaller. In other testing I've done, callback methods that call from C into Java have a similar or better speed increase (about 3.75x).

The Foreign API is only in incubator still, so it's subject to change. To support this API would require a multi-release jar. Using a tool like JExtract on sqlite3.h would do a large chunk of the translation required.

gotson commented 2 years ago

That sounds very promising. I've heard about Panama but never gave it a try.

However I don't see Panama replacing JNI in this repo. The API is still incubating, and will not land as stable before Java 19 or 20 probably. The current version supports Java 8.

Most of the recent work done in this repo is around the compilation of native libs (sqlite + JNI code) to multiple platforms, or some fixes in the JNI code or around it.

I don't think the 2 can coexist in the same repo easily.

I think however that a Panama fork would be most interesting. It would target higher JDKs, and replace JNI with Panama. Without the need to have a custom JNI code, you would only require the native SQlite library for your platform, which in itself could be complicated, given the variety of options to compile it, and making sure you have the right version. I'm thinking there could be 2 modules: the main one that would use the sqlite found on your system (or which you point at), and another module that would do what we do here, which is compiling the sqlite lib for multiple OSes and architectures, and make it available as resources inside the jar. That way if you want a similar behaviour as the current version, you can have it. But if you are happy to have sqlite as a dependency, using a package manager or something, you can too.

michael-o commented 2 years ago

Similar has been done recently for tomcat-native library. There the perf is on par with JNI code.

boulder-on commented 2 years ago

I like the idea of a separate fork to target more recent JDK's. Getting the existing repo to build using Java 17 and use the foreign API was not a simple drop in. The code has to be modularized to compile and, you need to provide the VM --enable-native-access [module names] in order to get anything to run.

I just started looking at the Java 18 early-access release and it looks like I already have to rewrite quite a bit of my code. I'm curious if something slowed down in 18 such that tomcat native didn't see much improvement, or if the jextract generated code needed optimizing.

boulder-on commented 2 years ago

I finally got around to making a fork with Panama. Not all of the unit tests are passing, but I think most of the failures are pretty benign. SQLite with Panama. The changes were all pretty minimal. There's still quite a bit of polish required, but it works.

I've only got the binaries compiled for Windows 64 bit and Linux 64 bit. Every other platform falls back to JNI.

gotson commented 2 years ago

For me the point of Panama is to not ship the lib with the jar, and use what's on the system already. That becomes easier because you don't need the small JNI part to be compiled, and you can rely on package managers to install the libs needed.

That's what I'm doing on my imageio project, NightMonkeys.

michael-o commented 2 years ago

For me the point of Panama is to not ship the lib with the jar, and use what's on the system already. That becomes easier because you don't need the small JNI part to be compiled, and you can rely on package managers to install the libs needed.

That's what I'm doing on my imageio project, NightMonkeys.

But what about macros and runtime checks?

gotson commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

michael-o commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

How are macros evaluated if you run jextract once, but all platforms are different.

gotson commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

How are macros evaluated if you run jextract once, but all platforms are different.

Still don't understand, sorry.

michael-o commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

How are macros evaluated if you run jextract once, but all platforms are different.

Still don't understand, sorry.

If the target header file contains: #ifdef __platform ...#endif and you run `jextract one platform, but not on the target one, how is this supported to properly detect everything?

gotson commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

How are macros evaluated if you run jextract once, but all platforms are different.

Still don't understand, sorry.

If the target header file contains: #ifdef __platform ...#endif and you run `jextract one platform, but not on the target one, how is this supported to properly detect everything?

Without concrete examples i don't really see what could be the impact. jextract is also optional.

michael-o commented 2 years ago

But what about macros and runtime checks?

Not sure to understand what you mean, can you provide same details / example ?

How are macros evaluated if you run jextract once, but all platforms are different.

Still don't understand, sorry.

If the target header file contains: #ifdef __platform ...#endif and you run `jextract one platform, but not on the target one, how is this supported to properly detect everything?

Without concrete examples i don't really see what could be the impact. jextract is also optional.

I'll try to provide an example the upcoming weeks. Maybe this is just an inconception from my side.

headius commented 1 year ago

I finally got around to making a fork with Panama

Hello there! I stumbled into this issue thanks to someone on Twitter who saw me whining about the performance of the JNI-based sqlite-jdbc. We use it heavily in JRuby to support the common use case of small local Rails apps that run on SQLite. Naturally we don't expect people to use SQLite in production, but having the JNI overhead makes it harder to benchmark the rest of Rails without spinning up a "real" database.

I am very excited that there's already work being done to support Panama! I was one of the originators of the project, and we plan to use it heavily in JRuby "very soon". In the short term, however, I would love to give some of our Rails benchmarks a run through with the Panama-based SQLite adapter. Is the fork by @boulder-on the best place to go right now?

boulder-on commented 1 year ago

I suspect that's the best place to look for now. The code as checked in can only run on Java 17. It would be possible to update to Java 18,19, or 20. If you'd prefer one of the other releases let me know. Each Java release has differences in the Panama API, which requires a different JPassport library.

michael-o commented 1 year ago

I finally got around to making a fork with Panama

Hello there! I stumbled into this issue thanks to someone on Twitter who saw me whining about the performance of the JNI-based sqlite-jdbc. We use it heavily in JRuby to support the common use case of small local Rails apps that run on SQLite. Naturally we don't expect people to use SQLite in production, but having the JNI overhead makes it harder to benchmark the rest of Rails without spinning up a "real" database.

I am very excited that there's already work being done to support Panama! I was one of the originators of the project, and we plan to use it heavily in JRuby "very soon". In the short term, however, I would love to give some of our Rails benchmarks a run through with the Panama-based SQLite adapter. Is the fork by @boulder-on the best place to go right now?

Why? What is wrong the the numerous Java-based embedded DBs?

enebo commented 1 year ago

@michael-o Ruby on Rails main DBs are sqlite3, mysql, and postgresql. Java embedded DBs are fine but Ruby users get sqlite3 as the default adapter which makes running it well more useful for people comparing C Ruby to JRuby.

michael-o commented 1 year ago

@michael-o Ruby on Rails main DBs are sqlite3, mysql, and postgresql. Java embedded DBs are fine but Ruby users get sqlite3 as the default adapter which makes running it well more useful for people comparing C Ruby to JRuby.

Thanks, from a Ruby point of view this is totally understandable, of course. The LCD is C.

ieugen commented 9 months ago

So openjdk 22 will ship with stable FFI API https://openjdk.org/projects/jdk/22/ . https://openjdk.org/jeps/454 .