1 Reply Latest reply on Dec 10, 2007 1:26 PM by Ales Justin

    VFS caching is broken

    Adrian Brock Master

      The VFS is using getLastModified() to determine whether
      the cache is valid. This is a broken check on Unix because deleting
      and replacing a file doesn't cause it to see the new file.

      Instead the file descriptor of the deleted file still exists in an unhooked state
      (i.e. not visible in the directory), until all references are released.

      Here's a test that shows the problem
      (basically doing what UndeployBrokenPackageUnitTestCase is doing).

      import java.io.File;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.net.URL;
      
      import org.jboss.util.file.Files;
      import org.jboss.virtual.VFS;
      import org.jboss.virtual.VirtualFile;
      
      public class Test
      {
       public static void main(String[] args) throws Exception
       {
       String testPackage = "ejbredeploy.jar";
       String temp = System.getProperty("java.io.tmpdir");
       File tempFile = new File(temp);
       URL tempURL = tempFile.toURL();
       File thejar = new File(tempFile, "ejbredeploy.jar");
       File badjar = new File(tempFile, "ejbredeploy-bad.jar");
       File goodjar = new File(tempFile, "ejbredeploy-good.jar");
      
      
       thejar.delete();
       Files.copy(badjar, thejar);
       VirtualFile child1 = printEjbJarXml(tempURL);
       System.out.println("child1 " + child1.getLastModified());
      
       Thread.sleep(1000);
      
       thejar.delete();
       Files.copy(goodjar, thejar);
       printEjbJarXml(tempURL);
       VirtualFile child2 = printEjbJarXml(tempURL);
      
       System.out.println("child1 " + child1.getLastModified());
       System.out.println("child2 " + child2.getLastModified());
       }
      
       public static VirtualFile printEjbJarXml(URL tempURL) throws Exception
       {
       VirtualFile file = VFS.getRoot(tempURL);
       VirtualFile child = file.findChild("ejbredeploy.jar/META-INF/ejb-jar.xml");
       InputStream is = child.openStream();
       InputStreamReader reader = new InputStreamReader(is);
       char[] buffer = new char[1024];
       int read = reader.read(buffer, 0, 1024);
       while (read >= 0)
       {
       for (int i = 0; i < read; ++i)
       System.out.print(buffer);
       read = reader.read(buffer, 0, 1024);
       }
       System.out.println();
      
       return child;
       }
       }
      


      To run it copy ejbredeploy-good.jar and ejbredeploiy-bad.jar into your temp directory.

      The output of the tests shows it does not see the replaced file
      and the last modified doesn't change
      so it must be holding onto the old file and never looking at the new file:

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE ejb-jar
       PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
       "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
      
      <ejb-jar>
       <description>An invalid single entity bean DD</description>
       <enterprise-beans>
       <entity>
       <description>EntityA</description>
       <ejb-name>EntityA</ejb-name>
      
       <home>org.jboss.test.jmx.interfaces.EntityAHome</home>
       <remote>org.jboss.test.jmx.interfaces.EntityA</remote>
      
       <ejb-class>org.jboss.test.jmx.ejb.EntityABean</ejb-class>
       <persistence-type>Container</persistence-type>
       <prim-key-class>java.lang.Integer</prim-key-class>
       <!-- Commenting these fields will make the deployment fail
       <reentrant>False</reentrant>
       <cmp-version>2.x</cmp-version>
       <abstract-schema-name>EntityA</abstract-schema-name>
       <cmp-field >
       <field-name>id</field-name>
       </cmp-field>
       <cmp-field>
       <field-name>value</field-name>
       </cmp-field>
       <primkey-field>id</primkey-field>
       -->
      
       </entity>
       </enterprise-beans>
      
      </ejb-jar>
      
      child1 1194256772000
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE ejb-jar
       PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
       "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
      
      <ejb-jar>
       <description>A valid single entity bean DD</description>
       <enterprise-beans>
       <entity>
       <description>EntityA</description>
       <ejb-name>EntityA</ejb-name>
      
       <home>org.jboss.test.jmx.interfaces.EntityAHome</home>
       <remote>org.jboss.test.jmx.interfaces.EntityA</remote>
      
       <ejb-class>org.jboss.test.jmx.ejb.EntityABean</ejb-class>
       <persistence-type>Container</persistence-type>
       <prim-key-class>java.lang.Integer</prim-key-class>
       <reentrant>False</reentrant>
       <cmp-version>2.x</cmp-version>
       <abstract-schema-name>EntityA</abstract-schema-name>
       <cmp-field >
       <field-name>id</field-name>
       </cmp-field>
       <cmp-field>
       <field-name>value</field-name>
       </cmp-field>
       <primkey-field>id</primkey-field>
      
       </entity>
       </enterprise-beans>
      
      </ejb-jar>
      
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE ejb-jar
       PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
       "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
      
      <ejb-jar>
       <description>A valid single entity bean DD</description>
       <enterprise-beans>
       <entity>
       <description>EntityA</description>
       <ejb-name>EntityA</ejb-name>
      
       <home>org.jboss.test.jmx.interfaces.EntityAHome</home>
       <remote>org.jboss.test.jmx.interfaces.EntityA</remote>
      
       <ejb-class>org.jboss.test.jmx.ejb.EntityABean</ejb-class>
       <persistence-type>Container</persistence-type>
       <prim-key-class>java.lang.Integer</prim-key-class>
       <reentrant>False</reentrant>
       <cmp-version>2.x</cmp-version>
       <abstract-schema-name>EntityA</abstract-schema-name>
       <cmp-field >
       <field-name>id</field-name>
       </cmp-field>
       <cmp-field>
       <field-name>value</field-name>
       </cmp-field>
       <primkey-field>id</primkey-field>
      
       </entity>
       </enterprise-beans>
      
      </ejb-jar>
      
      child1 1194256772000
      child2 1194256772000
      


        • 1. Re: VFS caching is broken
          Ales Justin Master

          I've been explaining this before - http://www.jboss.org/index.html?module=bb&op=viewtopic&t=122900 - that getLastModified is broken. :-)

          Since this is what I had to do in order to be able to delete file on Winz:

           public void testFileURLs()
           throws Exception
           {
           File tmp = File.createTempFile("testFileURLs", null);
           URL tmpURL = tmp.toURL();
           URLConnection conn = tmpURL.openConnection();
           InputStream in = conn.getInputStream();
           long lastModified;
           try
           {
           lastModified = conn.getLastModified();
           System.out.println("lastModified, "+lastModified);
           assertNotSame("lastModified", 0, lastModified);
           }
           finally
           {
           in.close();
           }
           assertTrue(tmp.getAbsolutePath()+" deleted", tmp.delete());
           conn = tmpURL.openConnection();
           lastModified = conn.getLastModified();
           System.out.println("lastModified after delete, "+lastModified);
           assertEquals("lastModified", 0, lastModified);
           }