Bug 57743 - Jar files in <webapp>/WEB-INF/lib are kept open, preventing redeploy
Summary: Jar files in <webapp>/WEB-INF/lib are kept open, preventing redeploy
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 8.0.20
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2015-03-23 12:57 UTC by Pavel Avgustinov
Modified: 2015-03-23 13:56 UTC (History)
0 users

A patch against AbstractResourceSet.java, adding a call to gc() when it is destroyed. (525 bytes, patch)
2015-03-23 12:57 UTC, Pavel Avgustinov
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Pavel Avgustinov 2015-03-23 12:57:51 UTC
Created attachment 32592 [details]
A patch against AbstractResourceSet.java, adding a call to gc() when it is destroyed.

As described in 56390, keeping jar files in a webapp folder open will prevent the application from being undeployed/redeployed on file systems which don't like open files to be deleted (in practice, that seems to mean Windows-based systems or NFS mounts).

Having observed the problem with tomcat 8.0.20, which is meant to contain the fix for 56390, I believe I have uncovered the root cause. Here's what happens, in my scenario:

 - A new .war is copied into $CATALINA_HOME/webapps; this is picked up by `HostConfig.checkResources()`, which decides to redeploy the app.

 - To do this, it first undeploys it (HostConfig.java:1250 in the TOMCAT_8_0_20 tag), and then attempts to delete the exploded war (line 1251).

 - In my case, the undeploy triggered a servlet's `destroy()` method, which triggered some class loading from WEB-INF/lib. Thus, the context's `WebResourceRoot` was used immediately before the attempt to delete the webapp folder, and opened a jar file.

 - Even though the `JarInputStreamWrapper` was properly closed, the handle to the jar remains open -- by design of `AbstractArchiveResource`, it is not closed immediately but with the next periodically scheduled call to `gc()`, as part of `StandardRoot.backgroundProcess()`.

As a result, when $CATALINA_HOME is on an NFS mount tomcat fails to delete the exploded webapp directory, and things go bad.

The attached patch fixes the problem in my testing; it simply changes `AbstractResourceSet.destroyInternal()` so that instead of doing nothing it calls `gc()`, which will close any jar files which no longer have open input streams. This seems like it's necessary to avoid a resource leak even on systems that allow the deletion of open files, since if I'm not mistaken after the context has been detached it will no longer receive `gc()` calls from the background process thread.
Comment 1 Mark Thomas 2015-03-23 13:56:24 UTC
Thanks for the very clear bug report and analysis.

Both the analysis and patch look good so the patch has been applied to trunk and 8.0.x for 8.0.21 onwards.

Thanks again for your contribution.