DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8645>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8645

Microsoft "Services for UNIX v2.0" nfs server has a corrupt last modification date

           Summary: Microsoft "Services for UNIX v2.0" nfs server has a
                    corrupt last modification date
           Product: Tomcat 3
           Version: 3.3.1 Final
          Platform: All
        OS/Version: Other
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: Webapps
        AssignedTo: [EMAIL PROTECTED]
        ReportedBy: [EMAIL PROTECTED]


This might or might not be Tomcat's problem, however I've found no 
documentation of this problem anywhere on the web, and Tomcat is severly 
affected. If Tomcat is behaving according to plan, then this bug report can be 
seen more as "for information purposes".

Microsoft's "Services for UNIX v2.0" http://www.microsoft.com/windows2000/sfu/ 
includes an NFS server amongst other things. This server has a big problem 
with last modification times of files. 

My setup is a Windows 2000 Server with Services for UNIX, sharing some folders 
using NFS to a Redhat Linux 7.2 box where I'm running tomcat on the NFS file 
system. 

It seems the NFS server sets the modification time twice for every update to 
the file. First when the NFS write is done to memory, and second when the 
change is flushed out to disk. I have verified that the second modification 
date change happens when I see a change in the NTFS file system. 

Consider the following shell excercise where we can see the modification date 
changing twice just using some normal shell tools:

$ pwd 
/home/martin

$ mount | grep /home/martin
winserv:/user_folders/martin on /home/martin type nfs (rw,hard,addr=10.8.0.2)

$ date ; echo "foo" >> bar ; ls --full-time bar
Tue Apr 30 09:42:21 BST 2002
-rw-rw-r--    1 martin   dev             4 Tue Apr 30 09:42:21 2002 bar

$ date ; ls --full-time bar
Tue Apr 30 09:42:31 BST 2002
-rw-rw-r--    1 martin   dev             4 Tue Apr 30 09:42:23 2002 bar


In words what we see is that the file gets a new modification time when I do 
the echo to the file. And roughly ten seconds later when I look at it again. 
The modification time has changed again (after that it stays as is). The 
second change is always around 2 seconds later.

Needless to say this has quite significant impacts on applications like 
Tomcat, where the modificaion time is used to determine reloads. The behaviour 
I'm seeing in Tomcat is along the lines of:

A) .jsp gets compiled to .java that gets compiled to .class
2002-04-30 09:03:12 - Ctx() : Compiling: /index.jsp to index_0

B) A dependency graph is built inside Tomcat using 
org.apache.tomcat.util.Dependecy and org.apache.tomcat.util.DependManager. The 
dependencies seems to be:
ROOT context -> .jsp
ROOT context -> .java 
ROOT context -> .class

C) At a later request the DependManager will validate the dependencies and 
finds the the .class file to have changed. (DependManager contains logging, 
but it is not possible to turn on without editing the class):
DependManager: Found expired file index_1.class
DependManager: ShouldReload5 E=true C=false

D) This triggers an invalidation of the whole dependency graph (my guess) that 
ultimatelly triggers the reload of the context:
2002-04-30 09:05:58 - ContextManager: Removing context 
martin.www.ioboxgroup.com.developer.taglab.com:/ROOT
2002-04-30 09:05:58 - Ctx() : Remove mapping
2002-04-30 09:05:58 - Ctx() : Remove mapping /index.jsp
2002-04-30 09:05:58 - ContextManager: Adding context 127.0.0.1:/ROOT

My webapps doesn't handle this reload very well, so this was a problem for me. 

Possible fixes:

1) Stop using crap Microsoft solutions.

2) Convince Microsoft to fix this problem (why does the phrase "move a 
mountain" spring to mind?)

3) Make the Dependency class tolerant for "minor changes" in the modification 
date. By testing I have concluded that the second update to the modification 
date seems to always be around 2 seconds after the first. The solution I've 
implemented locally allows for a 4 second change without doing a reload. This 
has of course the unwanted side effect that if I update say a JSP two times 
within 4 seconds, the server might not notice the second change. Arguably this 
is a fix for the symptoms and not the cause, and hence is probably nothing we 
would like to see in the Tomcat code base.

4) Should a change in the .class file really trigger a reload of the whole 
context? In the DependManager there is a concept of files being "local" or 
not "local". A change in a local is seemed to not be a reason to invalidate 
the whole Dependency manager. I am not sure I have all the facts about 
the "local" concept, but perhaps the .class file should be considered local, 
and hence not trigger context reloads?

Thanks,
Martin Algesten

Below is a diff of my current fix 3). I don't believe we want this in the code 
base but for reference:

$ diff -u Dependency.java-2002-04-29 Dependency.java
--- Dependency.java-2002-04-29  Mon Apr 29 19:30:17 2002
+++ Dependency.java     Mon Apr 29 19:30:49 2002
@@ -163,7 +163,26 @@
      *  be called to force a check for this particular dependency.
      */
     public boolean checkExpiry() {
-       if( lastModified < origin.lastModified() ) {
+
+        // Fix for broken Microsoft NFS, where the modification date
+        // gets set twice on a modification/creation of a file. First
+        // just after it has been updated and then again after approximatelly
+        // 2 seconds.
+
+        long o = origin.lastModified();
+
+        long t = o - lastModified;
+
+        // if the update was made in less that 4 seconds, then we ignore it
+        // and update our internal timestamp.
+        if ( t < 4000 ) {
+
+          lastModified = o;
+          return false;
+
+        }
+
+       if( lastModified < o ) {
            expired=true;
            return true;
        }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to