Non-blocking i/o

61 views
Skip to first unread message

Marshall Pierce

unread,
Jun 20, 2019, 11:00:03 AM6/20/19
to jooq...@googlegroups.com
Any idea when/if nonblocking i/o for db access will make percolate its
way through enough of a standardization process that jooq will expose
it? I'd love to be able to use jooq without having a threadpool around
to do blocking i/o on.

There's at least some activity on the mailing list ostensibly associated
with getting ADBA done:
http://mail.openjdk.java.net/pipermail/jdbc-spec-discuss/. Both pgadba
and pgnio both seem to be in a holding pattern waiting for ADBA to firm
up, though, and I think ADBA was last mentioned on the jooq blog on a
4/1 post. ;)

What I need to do now (in Kotlin + coroutines):

// toss the work into a thread pool for blocking i/o
val result = withContext(Dispatchers.IO) {
jooq.transactionResult { txn ->
// run queries here
}
}

API wise, it'd be sometimes convenient to have the callback provided to
`transactionResult` be a suspending function for nicer integration with
coroutines, but rearranging things to be based around CompletableFutures
would be just about everything I want, and I could probably build a
suspending helper function on top of that.

Lukas Eder

unread,
Jun 21, 2019, 1:30:26 PM6/21/19
to jOOQ User Group
Hi Marshall,

Thank you very much for your message.

jOOQ 3.12 (shipping in June/July 2019) will finally have ResultQuery<R> extend Publisher<R> and a new RowCountQuery type will extend Publisher<Integer> (both from reactive streams and JDK 9 Flow). The implementation is still JDBC bound, and thus blocking. In jOOQ 3.13, we'll finally look into abstracting over JDBC and binding to R2DBC and possibly ADBA. It was not reasonable to do this before at least R2DBC (which I estimate will be wildly more popular than ADBA) stabilised. They're stabilising now and are planning to release 1.0.GA in Q3/Q4 2019.

I've been much involved on the lists and behind the scenes with both R2DBC and ADBA to make sure all the more remote edge cases of JDBC usage, including e.g. SQL Server's mixed out parameter / result set / update count / exception streams can be supported also in the reactive world, where this makes even more sense than in JDBC.

In order to bind to R2DBC, we'll probably have to abstract away quite a bit of internals that are currently directly bound to JDBC. I can't say how much effort this will be, exactly, nor if we can cover the entirety of JDBC's scope, or jOOQ's current feature set. But I'm positive, we'll get a working demo out about when R2DBC goes live.

Notice also that reactive != asynchronous. There will be additional work in retrofitting jOOQ's current fetchAsync() and executeAsync() implementations to work with the reactive API. What this means exactly, I cannot say yet.

I hope this clarifies our roadmap a bit. Do note that for the time being, you will always be able to manually write the glue code between jOOQ and whatever async/reactive driver you're using, by using Query.getSQL() and Query.getBindValues().

Cheers,
Lukas

--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jooq-user/e7a4c55d-1ec8-5bfe-4745-dc36432b019f%40mpierce.org.
For more options, visit https://groups.google.com/d/optout.

Kevinjeet Gill

unread,
Jun 21, 2019, 2:55:29 PM6/21/19
to jOOQ User Group
Huh, interesting. I'd never heard about either R2DBC or ADBA. 

When libraries claim to be asynchronous or non-blocking, half of them just run all blocking calls in a background threadpool/FJPool and give you a nice "asynchronous" API for your "user code". While this might be good for convenience and pretty APIs, they often actually increase resource utilization (e.g elevate thread counts) and make them actually harder to manage! They're usually still 1 blocked thread per connection or inflight query.

"Real" asynchronous libraries use slightly more advanced facilities (epoll/nio/netty) to "batch" blocking IO calls and manage many more connections with a fixed 1 or 2 threads. One to two threads can send/receive on ALL sockets or connections efficiently and update all futures.

I can't tell from those project pages which approach they are taking. I understand that Jooq will probably operate in a level agnostic to those details but when talking about Flow or CompletableFuture API's it sorta emphasizes API ecosystems and doesn't seem to address implementation/architecture. 

Thanks!
To unsubscribe from this group and stop receiving emails from it, send an email to jooq...@googlegroups.com.

Lukas Eder

unread,
Jun 24, 2019, 3:41:44 AM6/24/19
to jOOQ User Group
On Fri, Jun 21, 2019 at 8:55 PM Kevinjeet Gill <kevinj...@gmail.com> wrote:
Huh, interesting. I'd never heard about either R2DBC or ADBA. 

I'm glad you did, now :)
 
When libraries claim to be asynchronous or non-blocking, half of them just run all blocking calls in a background threadpool/FJPool and give you a nice "asynchronous" API for your "user code". While this might be good for convenience and pretty APIs, they often actually increase resource utilization (e.g elevate thread counts) and make them actually harder to manage! They're usually still 1 blocked thread per connection or inflight query.

Well, here are my 2 cents:

1. Those APIs are far from pretty or convenient. They are at best useful. Compared to classic, synchronous, (and even imperative) code, they create a million lines of boiler plate, and difficult to understand indirections, which are hard to debug, especially when following the reactive model. "Why isn't my code executed?" Well good luck finding out which completely unrelated part of your very complex stream had an excess "Flux.distinctUntilChanged()" in it, that blocked all consumer updates.
2. The ugly truth in most cases is that those blocking calls are hardly a problem, even within a reactive stream, because the use-case of going asynchronous might have been overrated, at least in the domain of DB interactions in most ordinary applications.

At some point, we'll get this "right", even in Java. And I have a lot more hopes for project Loom than for these API driven solutions, because solving asynchronicity and reactiveness with APIs alone is going to clutter client code with tons of uninteresting and difficult to reason about infrastructure code. This is also something Oracle is thinking about. Should they push ADBA and make it *both* asynchronous (CompletionStage) and reactive (Flow), or should they bet on upgrading JDBC through Loom? Because if Loom keeps up with its promises, using JDBC in a coroutine style way seems *much* more compelling than relying on new SPIs and APIs.
 
"Real" asynchronous libraries use slightly more advanced facilities (epoll/nio/netty) to "batch" blocking IO calls and manage many more connections with a fixed 1 or 2 threads. One to two threads can send/receive on ALL sockets or connections efficiently and update all futures.

That just shows that problems are solved on the wrong level, again. We need language / platform level support for asynchronicity. If everyone solves this on their own, what we get is a huge mess.
 
I can't tell from those project pages which approach they are taking. I understand that Jooq will probably operate in a level agnostic to those details but when talking about Flow or CompletableFuture API's it sorta emphasizes API ecosystems and doesn't seem to address implementation/architecture. 

jOOQ will not worry about any such implementation specifics, because that's a can of worms I would not want to open (or maintain), see the epoll/nio/netty example. The good news is, R2DBC looks very promising and well designed. And it builds on top of a very good SPI: Reactive streams, which jOOQ 3.12 can depend on. So, if someone decides that a reactive streams based library like RxJava or Reactor is going to serve their needs, thanks to R2DBC, jOOQ can relatively easily bridge the client facing code (Reactor) with the database facing code (the R2DBC driver).

Note that jOOQ just acts as a bridge, just like in the synchronous case of JDBC. It will not worry about connection pooling, threading, what not. This is why jOOQ didn't have a solution yet, because there was no R2DBC to rely upon. It would have been unwise to bind directly to individual, non-official third party drivers, such as e.g. the many little "reactive" PostgreSQL drivers.

I hope this helps,
Lukas

Lukas Eder

unread,
Jun 24, 2019, 4:05:41 AM6/24/19
to jOOQ User Group


On Monday, June 24, 2019 at 9:41:44 AM UTC+2, Lukas Eder wrote:

At some point, we'll get this "right", even in Java. And I have a lot more hopes for project Loom than for these API driven solutions, because solving asynchronicity and reactiveness with APIs alone is going to clutter client code with tons of uninteresting and difficult to reason about infrastructure code. This is also something Oracle is thinking about. Should they push ADBA and make it *both* asynchronous (CompletionStage) and reactive (Flow), or should they bet on upgrading JDBC through Loom? Because if Loom keeps up with its promises, using JDBC in a coroutine style way seems *much* more compelling than relying on new SPIs and APIs.


Kevinjeet Gill

unread,
Jun 25, 2019, 1:28:45 AM6/25/19
to jOOQ User Group
Thanks for all the insight Lukas.

I'm excited for Loom as well and have been watching Ron's work keenly. I don't think they're at the stage to set a timeline, so I don't know if
it makes sense to plan around it yet.

To the best of my knowledge, as a coroutine/green thread system, Loom won't attempt to solve the problem of fusing multiple connections
into a single epoll. Any "async" db connector will have to solve that itself anyway, though Loom would would greatly simplify an efficient
implementation and the efficient use of one.

I'll read more into R2DBC.

Lukas Eder

unread,
Jun 25, 2019, 3:30:08 AM6/25/19
to jOOQ User Group
Sure, Loom won't solve everyone's problems automatically, but will (hopefully) provide the infrastructure for solving those problems. Imagine, a JDBC call to a Loom-enabled driver, that runs the query in a coroutine, and "yields" results rather than "returning" them, allowing for the JDBC calling thread/fiber/whatever to suspend and continue whenever there is a new row, set of rows, etc...

There would be no need for a complicated new programming paradigm based on difficult to learn and debug reactive APIs.

--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jooq-user/f3376231-a23a-4078-bbde-9da194664f8f%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages