-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Fix jar file reference close race condition #43257
Conversation
FYI @pcasaes if you can give it a shot: I've implemented this quickly and using the simplest scheme i.e. using the flip into negative value to bound the domain of reference count values. It has 2 strict requirements:
I hope I'm not making it too strict |
@mariofusco PTAL @dmlloyd too If you prefer me to use a parity bit or any other mechanism to simplify the reasoning here, any suggestion is welcome |
cedefae
to
31fc642
Compare
I've found another logic error in the original implementation for the virtual threading part, fixing it |
Re Lines 152 to 160 in 31fc642
I'm concerned re this because if |
@gsmet I have to check yet if we need some tests and counters to verify that after a reset of caches all the jar file ref are correctly nulled out or that a retained jar file ref (acquired by some thread, and not yet released) - after a reset of caches - it's correctly closed (and nulled out) after being released. |
Status for workflow
|
/** | ||
* Ask to close this reference. | ||
* If there are no readers currently accessing the jarFile also close it, otherwise defer the closing when the last reader | ||
* will leave. | ||
*/ | ||
void close(JarResource jarResource) { | ||
release(jarResource); | ||
void markForClosing(JarResource jarResource) { |
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.
This method doesn't really close the resource, but mark it as ready to be closed, now its method better reflect this behaviour.
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.
This comment should be in the code, not here :)
return; | ||
} | ||
// close must change the value into a negative one or zeroing | ||
if (referenceCounter.compareAndSet(count, addCount(-count, -1))) { |
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.
The referenceCounter
is turned into a negative value to indicate (in an idempotent way) that the resource has been marked to be closed.
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.
Same as above
if (localJarFileRefFuture != null && localJarFileRefFuture.isDone()) { | ||
JarFileReference jarFileReference = localJarFileRefFuture.join(); | ||
if (jarFileReference.acquire()) { | ||
return consumeSharedJarFile(jarFileReference, jarResource, resource, fileConsumer); | ||
} | ||
closingLocalJarFileRef = true; |
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.
The acquire failure implies that the reference is already marked to be closed.
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.
Again
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.
The former implementation was designed under the strong assumption that the close
method on the JarFileReference
was called once and only once. This issue demonstrates that this assumption was no longer true, so the main goal of this pull request is making the close
idempotent (or more precisely the markForClosing
since this is semantic of that method).
@gsmet @geoand This fix has been also already verified by @pcasaes, so I believe that this pull request is ready to be merged. |
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.
Let's merge this to be able to backport it to 3.14.4.
@mariofusco As for the comments, please add them in a follow-up PR, that we will merge and backport later.
Thanks for taking a look at this. |
Nice! Thanks a lot! |
Possible solution for #43158
This is fixing a potential race while virtual threads try to "help" and in-progress release by moving forward the shared atomic reference: we need to make sure that
JarFileReference
s cleanup don't mess up with a freshly jar file shared by the virtual thread.At the same time if there's an in progress jar file ref load from a platform thread, the virtual thread doesn't have to replace the in progress task.