Skip to content

8283660: Convert com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java finalizer to Cleaner#8311

Closed
bchristi-git wants to merge 29 commits intoopenjdk:masterfrom
bchristi-git:remove-finalizers
Closed

8283660: Convert com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java finalizer to Cleaner#8311
bchristi-git wants to merge 29 commits intoopenjdk:masterfrom
bchristi-git:remove-finalizers

Conversation

@bchristi-git
Copy link
Member

@bchristi-git bchristi-git commented Apr 20, 2022

Please review this change to replace the finalizer in AbstractLdapNamingEnumeration with a Cleaner.

The pieces of state required for cleanup (LdapCtx homeCtx, LdapResult res, and LdapClient enumClnt) are moved to a static inner class . From there, the change is fairly mechanical.

Details of note:

  1. Some operations need to change the state values (the update() method is probably the most interesting).
  2. Subclasses need to access homeCtx; I added a homeCtx() method to read homeCtx from the superclass's state.

The test case is based on a copy of com/sun/jndi/ldap/blits/AddTests/AddNewEntry.java. A more minimal test case might be possible, but this was done for expediency.

The test only confirms that the new Cleaner use does not keep the object reachable. It only tests LdapSearchEnumeration (not LdapNamingEnumeration or LdapBindingEnumeration, though all are subclasses of AbstractLdapNamingEnumeration).

Thanks.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Integration blocker

 ⚠️ Whitespace errors (failed with the updated jcheck configuration)

Issue

  • JDK-8283660: Convert com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java finalizer to Cleaner (Sub-task - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/8311/head:pull/8311
$ git checkout pull/8311

Update a local copy of the PR:
$ git checkout pull/8311
$ git pull https://git.openjdk.org/jdk.git pull/8311/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 8311

View PR using the GUI difftool:
$ git pr show -t 8311

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/8311.diff

Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 20, 2022

👋 Welcome back bchristi! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Apr 20, 2022

@bchristi-git The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Apr 20, 2022
@openjdk openjdk bot added the rfr Pull request is ready for review label Apr 20, 2022
@mlbridge
Copy link

mlbridge bot commented Apr 20, 2022

/* This class maintains the pieces of state that need (or are needed for)
* cleanup, which happens by calling cleanup(), or is done by the Cleaner.
*/
private static class CleaningAction implements Runnable {
Copy link
Contributor

Choose a reason for hiding this comment

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

This nested class might be more aptly named EnumCtx since it is used during the enumeration process.

The mention of the cleanup() method in the nested class javadoc is a bit ambiguous, it seems there should be a cleanup() method in the class, but it is in AbstractLdapNamingEnumeration.

The state field might also be renamed enumCtx.

this.homeCtx = homeCtx;
homeCtx.incEnumCount();
enumClnt = homeCtx.clnt; // remember
this.state.homeCtx.incEnumCount();
Copy link
Contributor

Choose a reason for hiding this comment

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

Readability might be improved by using the new homeCtx() method instead of state.homeCtx in this file.
It would then be consistent with how subclasses access it.
It depends which style you prefer to be more consistent with.

Copy link
Member

@dfuch dfuch left a comment

Choose a reason for hiding this comment

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

I also agree with Roger's suggestions.

@Override
public void run() {
if (enumClnt != null) {
enumClnt.clearSearchReply(res, homeCtx.reqCtls);
Copy link
Member

Choose a reason for hiding this comment

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

It's a bit strange to see that there is no guard here to verify that homeCtx != null, when line 76 implies that it might. My reading is that homeCtxt is not supposed to be null when enumClnt is not null. That could be explained in a comment, or alternatively asserted just before line 73 (assert homeCtx != null;)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is strange -- that code came from the finalizer. I will add an assert.

Copy link
Member Author

Choose a reason for hiding this comment

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

It appears that the update() method can set 'homeCtx' for 'ne' to null while leaving 'enumClnt' non-null (~L410).
Perhaps here, the clearSearchReply() call should only happen if both are non-null.

}
}

private CleaningAction state;
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if state should be final?

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense to me. cleanable can be final, too.

@bchristi-git
Copy link
Member Author

AbstractLdapEnumeration's mutable state brings the possibility of threading issues between the program and cleaner threads. I've added some threading-related changes to the fix. See my comment in the bug report for additional background.

Since synchronization may now happen on the cleaner thread, I've changed AbstractLdapEnumeration to use its own Cleaner instance instead of the shared cleaner, for added safety. There have been deadlocks in ldap cleanup in the past.

The added finally blocks led to a lot of indentation changes. The "hide whitespace" option might help with viewing the changes.

try {
LdapResult newRes = homeCtx().getSearchReply(enumCtx.enumClnt, enumCtx.res);
enumCtx.setRes(newRes);
if (enumCtx.res == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks odd, setting the value using synchronized, but reading it without.

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've added getters to EnumCtx, and a comment explaining why only setters are synchronized.

@mlbridge
Copy link

mlbridge bot commented Jun 2, 2022

Mailing list message from Hans Boehm on core-libs-dev:

On Wed, Jun 1, 2022 at 2:47 PM Roger Riggs <rriggs at openjdk.java.net> wrote:

...

214: } finally {
215: // Ensure Cleaner does not run until after this method
completes
216: Reference.reachabilityFence(this);

I don't think there is any benefit to the `try{} finally {fence}`.
The reachabilityFence has no executable code. Its only purpose is to keep
the reference in scope alive.

That's an interesting general question.

I agree that this is true with the right implementation assumptions, which
might conceivably be warranted here. But if there is a possibility that the
block throws after a point at which you need this to ensure reachability,
then I don't think this is spec-correct without the try-finally. Consider

tmp = a.field;
use(field); // Cleaner associated with a invalidates field
if (moon_phase() == FULL) throw(...);
Reference.reachabilityFence(a);

Consider the full moon case. The reachabilityFence spec says: "the
referenced object is not reclaimable by garbage collection at least until
after the invocation of this method." This method is not invoked, so there
is no guarantee, and hence this may fail.

And indeed, a compiler could conceivably rewrite this to

if (moon_phase() != FULL) {
tmp = a.field;
use(field); // Cleaner associated with a invalidates field
Reference.reachabilityFence(a);
} else {
tmp = a.field;
use(field); // Cleaner associated with a invalidates field <--
potential crash
throw(...);
}

in which case this might, on very rare occasions, actually fail in the
throwing case, since the reference a may not be kept in the else clause.

Hans

@RogerRiggs
Copy link
Contributor

Hans, thank for the detailed example. I had not fully considered the flow of control in the throwing case.

}
ncp.setNameInNamespace(dn);
return ncp;
} finally {
Copy link
Member

Choose a reason for hiding this comment

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

let's remove one redundant space after }

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 28, 2022

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

Not today, PullrequestCloserBot

@openjdk
Copy link

openjdk bot commented Nov 14, 2022

@bchristi-git this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout remove-finalizers
git fetch https://git.openjdk.org/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added merge-conflict Pull request has merge conflict with target branch and removed rfr Pull request is ready for review labels Nov 14, 2022
@bridgekeeper
Copy link

bridgekeeper bot commented Dec 12, 2022

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

Thanks for the reminder, bridgekeeper

@bridgekeeper
Copy link

bridgekeeper bot commented Jan 9, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

Keepalive

@stuart-marks
Copy link
Member

Reference.reachabilityFence(this)

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 7, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

ever diligent,
"Are you still working on this?"
asks bridgekeeper bot

@stuart-marks
Copy link
Member

Oh darn, looks like Reference.reachabilityFence(this) is broken!!

@bridgekeeper
Copy link

bridgekeeper bot commented Mar 8, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@stuart-marks
Copy link
Member

MethodHandles.lookup().findVarHandle(PR.class, "8311").acquireFence()

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 6, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

[Presses Snooze]

@bridgekeeper
Copy link

bridgekeeper bot commented May 6, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

Not yet

@bridgekeeper
Copy link

bridgekeeper bot commented Jun 8, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

Let's hang on to this for a bit longer

@bridgekeeper
Copy link

bridgekeeper bot commented Jul 8, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bchristi-git
Copy link
Member Author

July already!

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 14, 2023

@bchristi-git This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bridgekeeper
Copy link

bridgekeeper bot commented Sep 12, 2023

@bchristi-git This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the /open pull request command.

@bridgekeeper bridgekeeper bot closed this Sep 12, 2023
@bchristi-git
Copy link
Member Author

Your persistence finally paid off, bridgekeeper - well played.

@stuart-marks
Copy link
Member

"Who reviewth the PR of Death
Must answer me these questions three
Ere the PR reopened be."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core-libs core-libs-dev@openjdk.org merge-conflict Pull request has merge conflict with target branch

Development

Successfully merging this pull request may close these issues.

6 participants