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

Connection handling fixes #14305

Merged
merged 7 commits into from
Feb 25, 2021
Merged

Connection handling fixes #14305

merged 7 commits into from
Feb 25, 2021

Conversation

yrodiere
Copy link
Member

Fixes #7242, #13273.

I ended up keeping support for getTransaction() for now, since it still works. We can open another pull request if we want to drop it.

Opening as draft because:

  • The build is expected to fail for now; we need to upgrade to a version of ORM that includes HHH-14326 + HHH-14404 Connection closing fixes hibernate/hibernate-orm#3693 first.
  • We need some additional testing as a previous version of this patch used to trigger deadlocks in the database. The fixes in ORM may solve these deadlocks, but that's absolutely not certain since we haven't found the exact cause yet. @johnaohara is trying to reproduce the deadlocks.

@ghost ghost added area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE labels Jan 14, 2021
SessionBuilder<?> options = sessionFactory.withOptions()
.autoClose(true) // .owner() is deprecated as well, so it looks like we need to rely on deprecated code...
.connectionHandlingMode(
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_BEFORE_TRANSACTION_COMPLETION)
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain to me again why these options have to be set again here?

Copy link
Member Author

@yrodiere yrodiere Jan 18, 2021

Choose a reason for hiding this comment

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

Because managed, transaction-scoped sessions have different requirements from user-created sessions (direct calls to createEntityManager()) with manual transaction management (begin/commit).

Most important is the auto-close on transaction completion, which obviously only makes sense for transaction-scoped sessions. When a user calls .createEntityManager() manually, you'd expect them to close the EM manually.

For other settings, it's really about backward compatibility. From what I can see in FastBootMetadataBuilder we still allow custom settings for all sorts of properties (from persistence.xml?), and while other connection handling modes could make sense for manually-created entity managers, I don't think they would for transaction-scoped sessions.
This solution allows us to force these settings for transaction-scoped sessions, while preserving the ability to override them for manually-created entity managers.

To sum up, we could limit this to only setting autoClose(true) here, and assume that people setting the connection handling mode and other related settings manually know what they are doing.

@yrodiere
Copy link
Member Author

@johnaohara gave the green light for merging this. I just rebased my branch. @Sanne , as soon as you're good with my answer to your review, we can go ahead and merge :)

Thanks to @johnaohara and @barreiro for looking into this!

yrodiere and others added 4 commits February 22, 2021 14:50
Signed-off-by: Yoann Rodière <yoann@hibernate.org>
Signed-off-by: Yoann Rodière <yoann@hibernate.org>
DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT, on top of being less
efficient, also leads to resource leaks (that are caught by Agroal,
but still).

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
@yrodiere
Copy link
Member Author

yrodiere commented Feb 22, 2021

There were a few problems with multi-tenancy, so I switched to a safer (and, I think, cleaner) approach in the last commit. It should be good now.

We were doing that through an extra transaction synchronization, but
there's no need since Hibernate ORM has built-in features to handle
that.

Note that without this patch:

1. Hibernate ORM flushes before transaction completion.
2. Then Hibernate ORM closes the connection wrapper.
3. Then Quarkus flushes again in its own synchronization, which
   usually does nothing, but in some cases (when the dirtiness of some
   entities cannot be known, for example when there are mutable
   @converted properties) it will execute the updates again...
   This is problematic in itself, but it will also lead to acquiring a
   new connection wrapper from Agroal, which will not be closed.
4. Then when the commit happens, Agroal notices a connection wrapper was
   not closed and logs a warning.

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
The call to joinTransaction() is not necessary, the Session already
joins the transaction when it starts.

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
…e for non-injected sessions

With this patch, hopefully people can safely use
EntityManagerFactory.createEntityManager() and opening transactions
manually?

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
@yrodiere
Copy link
Member Author

Fixed another test, apparently the metrics module was expecting two flushes for a single transaction. That's actually a problem that I fixed in this PR: we now correctly only flush once. I changed the test so that it passes.

Relevant commit: Let Hibernate ORM handle the flush/close after a transaction.

@Sanne
Copy link
Member

Sanne commented Feb 23, 2021

Fixed another test, apparently the metrics module was expecting two flushes for a single transaction. That's actually a problem that I fixed in this PR: we now correctly only flush once

Very nice!

}
}
cfg.putIfAbsent(AvailableSettings.CONNECTION_HANDLING,
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_BEFORE_TRANSACTION_COMPLETION);
Copy link
Member

Choose a reason for hiding this comment

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

N.B. that semantics is not the same: the key can be defined while the value is set to null. No? Or is the change intentional?

Copy link
Member Author

Choose a reason for hiding this comment

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

If it's a problem here, it's probably also a problem just above, where we use cfg.containsKey to check whether a property is defined or not.

If we're going to worry about this, I think what we need to ask is: how would we end up in a situation where a property is set, but its value is null? From what I understand the only way for properties to be pre-set here is from a persistence.xml. I'm not sure if you can set something to null from persistence.xml?

@Sanne
Copy link
Member

Sanne commented Feb 23, 2021 via email

@Sanne Sanne added the triage/qe? Issue could use a quality focused review to further harden it label Feb 25, 2021
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.

Great work, thanks!

@Sanne Sanne added this to the 1.13 - master milestone Feb 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE triage/qe? Issue could use a quality focused review to further harden it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improved efficiency of ConnectionHandlingMode: deeper integration between Hibernate ORM and Agroal
2 participants