VFS caching is broken
adrian.brock Dec 10, 2007 1:11 PMThe 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