-
-
Notifications
You must be signed in to change notification settings - Fork 102
[4.2] Open connections lazily #2690
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
base: main
Are you sure you want to change the base?
Conversation
| return connection().thenCompose( conn -> conn | ||
| .insertAndSelectIdentifier( sql, paramValues, idClass, idColumnName ) ); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
ReactiveConnection.insertAndSelectIdentifier
| return connection().thenCompose( conn -> conn | ||
| .insertAndSelectIdentifierAsResultSet( sql, paramValues, idClass, idColumnName ) ); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
ReactiveConnection.insertAndSelectIdentifierAsResultSet
hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
Outdated
Show resolved
Hide resolved
|
|
||
| @Override | ||
| public DatabaseMetadata getDatabaseMetadata() { | ||
| Objects.requireNonNull( connection, "Database metadata not available until the connection is opened" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I'm throwing a NullPointerException here for now if they try to getDatabaseMetadata without a connection
ed416b8 to
0dee152
Compare
0dee152 to
6ff2498
Compare
Print the exception when there's an error in MultithreadedInsertionTest
6ff2498 to
b1c5be0
Compare
|
After looking into it, I figured out that the test I added for the id generation fails because the event loop thread changes during the execution when using the lazy connection approach. The test was getting stuck because of an error in the session.close method. @yrodiere what should we do? Merge these changes and fixed the issues later? Or wait until we figure out how to solve this?
@tsegismont, maybe you can help with this? |
I think we should investigate before merging, at least. I have a few questions:
|
Looking at the code... when opening the connection eagerly we do this: Lines 122 to 127 in a8662c9
... which means that call In the lazy connection opening case, we first call So... I think you've uncovered a pre-existing bug, which is: we potentially switch to another event loop on connection opening. It's bad in both the lazy and eager connection opening cases, but it's only caught by our check with lazy connection opening. |
I'm not sure about this, the error happens when the session gets closed, if that's the reason of the failure, wouldn't that happen during the persist? But maybe there's something wrong when we close the session. In any case, I will look into it. |
Good point. Perhaps related... I found this code: Lines 74 to 76 in a8662c9
It's fine, but hints that something specific is needed to keep things on the same event loop, especially when dealing with completion stages. So... I'm entirely unsure what happens when you're not using Mutiny and thus not using this code to make sure everything runs in the same event loop. Which is precisely the case in this test, since it relies on completion stages instead of Mutiny. Did you try to convert this test to use mutiny APIs instead, see if it solves the problem? |
What's the question exactly? |
We had some discussions in the past about removing the checks because they are too strict. I'm not sure why we didn't remove them in the past and why we didn't have more issues related to this. I think it's an Hibernate Reactive issue, but maybe you can let us know if there's something else that we are missing. |
|
I'm going to merge this because I think it solves the issue. And after #2494 is done, we will be able to remove the checks (I think). |
|
I doubt we can remove this sort of check. We need to be sure that we're always being called with the same Vert.x duplicated context, otherwise we open ourselves up to very subtle bugs. |
But we're not checking we're called with the same Vert.x context, just that we're running in the same thread. Which is no longer relevant after #2494... ? |
I get that, but in the past (I believe) the only way we could be sure we were in the same duplicated context was to be on the same thread.
Can you give me a summary of what changed there? |
AFAIK being on the same thread is no guarantee you're still using the same context. Threads can switch context back and forth. But, more to the point... I don't know about before, but right now we are storing the current thread in a variable and later checking the current thread is still the same. We could just change that to store/check the current vert.x context instance, e.g. Or am I missing some obvious reason we're checking the thread instead?
We would make sure that if you trigger two calls on the session, they will never interleave. E.g. here: return sessionFactory.withSession(s -> {
return Uni.combine().combine().all().unis(s.doSomething(), s.doSomethingElse()).asTuple();
});
If we make absolutely sure that That's the specific problem #2494 intends to fix, and it's mostly irrelevant to the thread check. But the solution mentioned in #2494 would help for another (worse) problem. If we have the thread check, it means we assume callbacks could possibly be executed on different event loops (and given the failure Davide encountered, it's indeed possible). If that's possible, then the code above could result in tasks/callbacks being executed in parallel, not just interleaved. With all the concurrency problems this implies. Fortunately if this "serialization" of calls is enforced, even switching threads we're sure we will never execute operations in parallel. Hence the thread switching is no longer relevant. Now, the Vert.x context switching still very much is, I'll grant you that. See above :) |
Of course. That's certainly correct. The implication was in the other direction: that Vert.x was supposed to guarantee thread affinity for callbacks. And so if it was a different thread, we knew something was wrong.
That's just the Vert.x context. Not the duplicated context AFAIK.
Well it would, for sure, but it wouldn't tell us anything about the duplicated context. |
|
At the risk of stating the obvious, a duplicated context is a context, and if you're using the same context you're using the same duplicated context. I feel like we're running in circles, so maybe let's have a talk to discuss this? |
If this is the case then something has changed in a fundamental way since I last looked at all this. That definitely wasn't true when this code was written. |
|
I talked to @gavinking and removing the check after #2494 is probably too bold. So let's not. I created #2736 to address the check issue one way or another; we can work on that as our next step. |
Fix #2518
This PR add the following methods to the Mutiny and Stage API:
I've annotated them with
@Incubating.Overall, it seems to work fine. But I decided to add a test that mimic the id generation and, if I don't use transactions, it seems to get stuck (even with a low number of ids). I don't know why. The same test seems to work fine when the connection is not opened lazily. It's possible that there's something wrong with the test.
I've applied the changes that make the test fail on a different branch: b511efa
Basically, if I call
persistand thenflush, instead ofwithTransaction, the test get stuck (the test isMultithreadedInsertionWithLazyConnectionTest)openSessionWithLazyConnectionseems a bit of a mouthful but I don't have strong opinions about it.Originally, it was called only
createSession.