Jesse, could you please implement it as you suggested in #20323?
It might be possible in case a module is about to be deleted to create
a copy in /tmp (File.createTempFile) of all the JARs the classloader
had open, open the copy JARs, close the originals, and switch the
JarFile's used internally. Also, if and when the classloader is
finalized, close the copy JARs and delete them.
Created attachment 4925 [details]
I have partially solved this - at least the NB side of things. With
the attached patch, the module classloader does not keep an open
JarFile for the module after it has been deleted.
However it is not enough. As I found out, if a jar: URL is *ever*
opened in the VM, private JRE code keeps a hard reference to an open
JarFile for that JAR and never releases it! This means that if the
module classloader ever serves a request for ClassLoader.getResource
(which almost every module will), using a jar: URL, and the module is
not marked reloadable, the JAR will not be deletable (or upgradable)
in this VM session on Windows.
I filed a Java bug, will attach a URL when it is accepted.
The new unit test demonstrates the problem. It passes on Unix but
fails on Windows.
I can think of two possible ways to continue:
1. Do not use jar: URLs. Define and use a custom URL protocol which
behaves much like jar: but uses NB-specific knowledge about when a JAR
should be closed. After the JAR is closed (e.g. because of
ModuleManager.delete), it could be copied to a temp dir to serve old
URL connection requests. Pros: safe; we may want to do similar manual
rerouting of JAR entry requests in order to implement a fast JAR cache
at startup anyway. Cons: some work to implement; duplication of a lot
of JRE code.
2. Using reflection, delete entries from JarFileFactory.fileCache when
ModuleManager.delete is called, to make sure that no open JarFile is
retained. It would still be possible for "zombie" code in a dead
classloader to ask for URL resources from the module, but the patched
JarClassLoader would serve them from the copy JAR, making it possible
to still delete the original. Pros: simple and may be effective. Cons:
dangerous call to private impl code, cannot be guaranteed to work in
future JDK releases.
I will try to solve the problem using #2 for now. If we want to
implement JAR caches later for reasons of startup performance, it may
be worthwhile to rewrite to code to use style #1.
Java bug: #4646668
OK, using workaround #2 (reflection hack). Seems to work well enough
with JDK 1.3.0 and 1.4.0 on Win2000. Also does not seem to hurt
anything on Linux with JDK 1.3.1_02 nor 1.4.0 (though the fix is not
really necessary on Unix systems anyway). Will commit soon.
Ales - note that the JAR locks are released only after the module is
really deleted from the ModuleManager pool. They are *not* released
after just disabling a module. From Auto Update, you should be able to
do this: delete the Modules/*.xml file corresponding to the module;
listen for changes in the Lookup result on ModuleInfo and wait for the
module to disappear from the list (with some sanity timeout of
course); then physically delete the JAR. The same system should work
for other JARs associated with the module: declared Class-Path
extensions, locale/branding variants, and
modules/patches/module-code-name/ patch JARs.
Also Ales - please run the usual unit test suite on Windows after I
commit (you run Windows, correct?). I ran ModuleManagerTest in
isolation on Win2K because I do not have full XTest set up on that
partition, but it would be good to make sure everything (esp. the new
ModuleManagerTest.testModuleDeletion) passes OK for you as well,
especially using JDK 1.3.1. Since reflection is used, it is possible
for a random JDK to not have the same impl of jar: URL caching, in
which case JarClassLoader will print an exception to the log file, and
the fix will be disabled. I found that 1.3.0 seems to have a slightly
different impl from 1.3.1 and 1.4.0 - the fileCache field became
committed * Up-To-Date 1.8
committed * Up-To-Date 1.23
committed * Up-To-Date 1.25
committed * Up-To-Date 1.15
committed * Up-To-Date 1.6