-
Notifications
You must be signed in to change notification settings - Fork 306
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
CUSTCOM-76: Fix Thread synchronization in WebappClassloader #4378
Conversation
import org.apache.naming.resources.WebDirContext; | ||
import org.apache.naming.resources.Resource; | ||
import org.apache.naming.resources.ResourceAttributes; | ||
import org.apache.naming.resources.*; |
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.
I would stay with a list of classes if it is less than 11.
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.
That's up for debate - personally I hate using *
unless I'm literally using every single class :P
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.
Yes, my experience is that if you use more than 10 classes from the same package in imports, usually the new class asks to be refactored, so finally we end up in the same nice state :)
@@ -837,56 +838,58 @@ public synchronized void addJar(String jar, JarFile jarFile, File file) | |||
logger.log(Level.FINER, "addJar({0})", jar); | |||
} | |||
|
|||
// See IT 11417 | |||
super.addURL(getURL(file)); | |||
synchronized (jarFilesPropertyLock) { |
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 method is already synchronized, how could this help? Two locks can cause deadlock ... but ... in previous version jarFiles are used also as a lock, so that's the same ...
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 method addJar() is synchronized, but other parts of the class requires synchronized access to the property jarFiles. But the synchronization on the method does not synchronize on the property.
In this class, there are synchronization block on 6 different items.
@@ -2711,7 +2729,7 @@ protected ResourceEntry findResourceInternal(String name, String path) { | |||
entry = findResourceInternalFromRepositories(name, path); | |||
|
|||
if (entry == null) { | |||
synchronized (jarFiles) { |
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.
Wouldn't be better to extract the synchronized block to a synchronized method, so it would use the same "default" lock?
Or all accesses to the final field should use own but same lock as you implemented, but I would be afraid of deadlocks ... or use Concurrent implementation if it would make sense (I don't think it does here).
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.
I don't want to change the synchronization fundamentally since there seems a lot of synchronization logic in the code. And changing those things means that we probably break the server functionality.
Were you able to confirm that the race condition is between My hypothesis would be that it is race condition between
Payara/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java Line 2838 in c290512
Payara/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java Line 2561 in c290512
But before Payara/appserver/web/war-util/src/main/java/org/glassfish/web/loader/WebappClassLoader.java Line 1929 in c290512
It synchronizes on same lock liken |
@pdudits But I'll add it since it can lead to some issues in the future. |
But |
I used to the (already present) jarFilesLock object within the findResourceInternalFromJars method since that one was already protecting the access to property jarFiles. |
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.
Looking with "Hide whitespace changes" turned on, the change looks good.
But this one passage from indented part really bothers me:
String[] result = new String[paths.length + 1]; | ||
for (int i = 0; i < paths.length; i++) { | ||
result[i] = paths[i]; | ||
} | ||
result[paths.length] = jar; | ||
paths = result; |
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.
These 4 idioms for appending arrays are quite disturbing here.
The design might stem from pre-1.4 era, where there was nothing similar to CopyOnWriteArrayList<PathEntry>
, and is instead simulated with multiple arrays. But these should at least be refactored into form paths = appendArray(paths, entry)
. And internally use Arrays.copyOf(arr, arr.length+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.
Correct, but the goal of this PR is not to update some already existing code constructs.
But jars are reopened immediately again to have the classloader working. So not an efficient part of this old code. |
Customer verified custom build with this changes and reports issue is fixed. Good to be merged in master |
Jenkins test please |
Description
This is a bug fix
Customer reports occasionally a NullPointerException in
org.glassfish.web.loader.WebappClassLoader
when starting up his Payara Micro (5.193.1) Application.There is a synchronized access on a non final property causing multithreading issues in the addJar() and findResourceInternalFromJars()
Testing
New tests
Testing Performed
Test suites executed
Testing Environment
Oracle 8u181, mvn 3.5.4
Documentation
N/A
Notes for Reviewers
Also added {} to if statements if missing.
Update 16/12
I used to the (already present) jarFilesLock object within the
findResourceInternalFromJars
method since that one was already protecting the access to propertyjarFiles
.This means that accessing the jar files is now synchronized with start up but also with shutdown.