Revision: 9977
Author:   [email protected]
Date:     Tue Apr 12 07:43:39 2011
Log: Addresses ClassNotFoundException problems when the data structures serialized in
the unit cache log files no longer matches due to changes in GWT.

Review at http://gwt-code-reviews.appspot.com/1412801

http://code.google.com/p/google-web-toolkit/source/detail?r=9977

Modified:
 /trunk/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
 /trunk/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java Thu Mar 31 08:40:20 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java Tue Apr 12 07:43:39 2011
@@ -266,7 +266,7 @@
    */
   static final String UNIT_CACHE_PREFIX = "gwt-unitCache";

-  static final String CACHE_PREFIX = UNIT_CACHE_PREFIX + "-";
+  static final String CACHE_FILE_PREFIX = UNIT_CACHE_PREFIX + "-";

   /**
    * If there are more than this many files in the cache, clean up the old
@@ -310,7 +310,7 @@
     long timestamp = System.currentTimeMillis();
     do {
       currentCacheFile =
- new File(cacheDirectory, CACHE_PREFIX + String.format("%016X", timestamp++)); + new File(cacheDirectory, CACHE_FILE_PREFIX + String.format("%016X", timestamp++));
     } while (currentCacheFile.exists());

     // this isn't 100% reliable if multiple processes are in contention
@@ -424,7 +424,7 @@
       File[] files = cacheDirectory.listFiles();
       List<File> cacheFiles = new ArrayList<File>();
       for (File file : files) {
-        if (file.getName().startsWith(CACHE_PREFIX)) {
+        if (file.getName().startsWith(CACHE_FILE_PREFIX)) {
           cacheFiles.add(file);
         }
       }
@@ -460,6 +460,7 @@
           if (cacheFile.equals(currentCacheFile)) {
             continue;
           }
+          boolean deleteCacheFile = false;
           try {
             fis = new FileInputStream(cacheFile);
             bis = new BufferedInputStream(fis);
@@ -487,15 +488,21 @@
           } catch (EOFException ex) {
             // Go on to the next file.
           } catch (IOException ex) {
- logger.log(TreeLogger.WARN, "Error reading cache file: " + cacheFile.getAbsolutePath(),
-                ex);
+            deleteCacheFile = true;
+            logger.log(TreeLogger.TRACE, "Ignoring and deleting cache log "
+                + cacheFile.getAbsolutePath() + " due to read error.", ex);
           } catch (ClassNotFoundException ex) {
- logger.log(TreeLogger.ERROR, "Error deserializing CompilationUnit in "
-                + cacheFile.getAbsolutePath(), ex);
+            deleteCacheFile = true;
+            logger.log(TreeLogger.TRACE, "Ignoring and deleting cache log "
+ + cacheFile.getAbsolutePath() + " due to deserialization error.", ex);
           } finally {
             Utility.close(inputStream);
             Utility.close(bis);
             Utility.close(fis);
+          }
+          if (deleteCacheFile) {
+            cacheFile.delete();
+          } else {
logger.log(TreeLogger.TRACE, cacheFile.getName() + ": Load complete");
           }
         }
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java Thu Mar 31 08:40:20 2011 +++ /trunk/dev/core/test/com/google/gwt/dev/javac/PersistentUnitCacheTest.java Tue Apr 12 07:43:39 2011
@@ -22,13 +22,32 @@
 import junit.framework.TestCase;

 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;

 /**
  * Unit test for {@link PersistentUnitCache}.
  */
 public class PersistentUnitCacheTest extends TestCase {

+ private static class ThrowsClassNotFoundException implements Serializable {
+    @SuppressWarnings("unused")
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+      throw new ClassNotFoundException();
+    }
+  }
+
+  private static class ThrowsIOException implements Serializable {
+    @SuppressWarnings("unused")
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+      throw new IOException();
+    }
+  }
+
   File lastCacheDir = null;

   public void tearDown() {
@@ -39,22 +58,17 @@
   }

   /**
-   * The cache should recursively create the directories it needs.
+ * When a cache file encounters a serialization error, the logic should assume
+   * the cache log is stale and remove it.
    */
-  public void testNewDir() throws IOException, UnableToCompleteException {
-    TreeLogger logger = TreeLogger.NULL;
-    File baseDir = File.createTempFile("PersistentUnitTest-newDir", "");
-    assertNotNull(baseDir);
-    assertTrue(baseDir.exists());
-    assertTrue(baseDir.delete());
-    File newDir = lastCacheDir = new File(baseDir, "sHoUlDnOtExi57");
-    new PersistentUnitCache(logger, newDir);
-    assertTrue(newDir.isDirectory());
+ public void testClassNotFoundException() throws IOException, UnableToCompleteException,
+      InterruptedException {
+    checkInvalidObjectInCache(new ThrowsClassNotFoundException());
   }

   /**
-   * Test if a file already exists with the name we want to put the
-   * cache dir in.
+ * Test if a file already exists with the name we want to put the cache dir
+   * in.
    */
   public void testFileInTheWay() throws IOException {
     TreeLogger logger = TreeLogger.NULL;
@@ -68,21 +82,37 @@
     } catch (UnableToCompleteException expected) {
     }
   }
+
+  /**
+   * If a cache file has some kind of IO exception, (this can happen with a
+ * stale cache file), then the exception should be ignored and the cache file
+   * removed.
+   */
+ public void testIOException() throws IOException, UnableToCompleteException, InterruptedException {
+    checkInvalidObjectInCache(new ThrowsIOException());
+  }
+
+  /**
+   * The cache should recursively create the directories it needs.
+   */
+  public void testNewDir() throws IOException, UnableToCompleteException {
+    TreeLogger logger = TreeLogger.NULL;
+    File baseDir = File.createTempFile("PersistentUnitTest-newDir", "");
+    assertNotNull(baseDir);
+    assertTrue(baseDir.exists());
+    assertTrue(baseDir.delete());
+    File newDir = lastCacheDir = new File(baseDir, "sHoUlDnOtExi57");
+    new PersistentUnitCache(logger, newDir);
+    assertTrue(newDir.isDirectory());
+  }

public void testPersistentCache() throws IOException, InterruptedException,
       UnableToCompleteException {
     TreeLogger logger = TreeLogger.NULL;

-    File cacheDir = null;
- lastCacheDir = cacheDir = File.createTempFile("persistentCacheTest", "");
-    assertNotNull(cacheDir);
-    // Wait, this needs to be a directory, not a file.
-    assertTrue(cacheDir.delete());
-    // directory will get cleaned up in tearDown()
-    assertTrue(cacheDir.mkdir());
-
- File unitCacheDir = new File(cacheDir, PersistentUnitCache.UNIT_CACHE_PREFIX);
-    assertNull(unitCacheDir.list());
+ File cacheDir = lastCacheDir = File.createTempFile("persistentCacheTest", "");
+    File unitCacheDir = mkCacheDir(cacheDir);
+
     PersistentUnitCache cache = new PersistentUnitCache(logger, cacheDir);

MockCompilationUnit foo1 = new MockCompilationUnit("com.example.Foo", "Foo: source1");
@@ -204,4 +234,38 @@
   private void assertNumCacheFiles(File unitCacheDir, int expected) {
     assertEquals(expected, unitCacheDir.list().length);
   }
-}
+
+ private void checkInvalidObjectInCache(Object toSerialize) throws IOException, + FileNotFoundException, UnableToCompleteException, InterruptedException {
+    TreeLogger logger = TreeLogger.NULL;
+ File cacheDir = lastCacheDir = File.createTempFile("PersistentUnitTest-CNF", "");
+    File unitCacheDir = mkCacheDir(cacheDir);
+
+    /*
+ * Create a cache file that has the right filename, but the wrong kind of
+     * object in it.
+     */
+ File errorFile = new File(unitCacheDir, PersistentUnitCache.CACHE_FILE_PREFIX + "12345"); + ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(errorFile));
+    os.writeObject(toSerialize);
+    os.close();
+
+    assertNumCacheFiles(unitCacheDir, 1);
+
+    PersistentUnitCache cache = new PersistentUnitCache(logger, cacheDir);
+    cache.cleanup(logger);
+    cache.shutdown();
+
+    // The bogus file should have been removed.
+    assertNumCacheFiles(unitCacheDir, 0);
+  }
+
+  private File mkCacheDir(File cacheDir) {
+    assertNotNull(cacheDir);
+    assertTrue(cacheDir.exists());
+    cacheDir.delete();
+ File unitCacheDir = new File(cacheDir, PersistentUnitCache.UNIT_CACHE_PREFIX);
+    unitCacheDir.mkdirs();
+    return unitCacheDir;
+  }
+}

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to