Revision: 9885
Author:   scheg...@google.com
Date:     Wed Mar 23 12:56:08 2011
Log:      Using cached ZipFileClassPathEntry objects.

While this does not give benefits for DevMode, which parses jar files only once, GWT Designer does this many times.
This gives about 15% speed up in GWT Designer.

Initial.
-------------
Parsing...done: 4775
refresh: 296
palette: 114
Parsing...done: 2445
refresh: 274
palette: 38
Parsing...done: 2396
refresh: 272
palette: 37

Cache ZipFileClassPathEntry
-------------
Parsing...done: 4299
refresh: 304
palette: 116
Parsing...done: 2161
refresh: 277
palette: 41
Parsing...done: 2087
refresh: 270
palette: 38

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

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

Modified:
/trunk/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java /trunk/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java /trunk/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java /trunk/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java Thu Feb 10 07:58:19 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java Wed Mar 23 12:56:08 2011
@@ -156,14 +156,14 @@
       if (f.isDirectory()) {
         return new DirectoryClassPathEntry(f);
       } else if (f.isFile() && lowerCaseFileName.endsWith(".jar")) {
-        return new ZipFileClassPathEntry(f);
+        return ZipFileClassPathEntry.get(f);
       } else if (f.isFile() && lowerCaseFileName.endsWith(".zip")) {
-        return new ZipFileClassPathEntry(f);
+        return ZipFileClassPathEntry.get(f);
       } else {
         // It's a file ending in neither jar nor zip, speculatively try to
         // open as jar/zip anyway.
         try {
-          return new ZipFileClassPathEntry(f);
+          return ZipFileClassPathEntry.get(f);
         } catch (Exception ignored) {
         }
         logger.log(TreeLogger.TRACE, "Unexpected entry in classpath; " + f
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java Fri Mar 18 10:49:05 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java Wed Mar 23 12:56:08 2011
@@ -22,6 +22,10 @@
 import com.google.gwt.dev.util.collect.Sets;
 import com.google.gwt.dev.util.msg.Message1String;

+import org.apache.commons.collections.map.AbstractReferenceMap;
+import org.apache.commons.collections.map.ReferenceIdentityMap;
+import org.apache.commons.collections.map.ReferenceMap;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Enumeration;
@@ -65,19 +69,47 @@
       this.cachedAnswers = cachedAnswers;
     }
   }
+
+  /**
+ * Memory-sensitive cache of indexed {@link ZipFileClassPathEntry}s. URI of file is most probably + * not referenced anywhere else, so we use hard reference, and soft reference on + * {@link ZipFileClassPathEntry} allows its clearing in response to memory demand.
+   */
+  @SuppressWarnings("unchecked")
+ private static final Map<String, ZipFileClassPathEntry> entryCache = new ReferenceMap(
+      AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
+
+  /**
+ * @return the {@link ZipFileClassPathEntry} instance for given jar or zip
+   *         file, may be shared with other users.
+   */
+ public static synchronized ZipFileClassPathEntry get(File zipFile) throws IOException {
+    String location = zipFile.toURI().toString();
+    ZipFileClassPathEntry entry = entryCache.get(location);
+    if (entry == null) {
+      entry = new ZipFileClassPathEntry(zipFile);
+      entryCache.put(location, entry);
+    }
+    return entry;
+  }

   private Set<ZipFileResource> allZipFileResources;

   /**
-   * Currently gwt has just 2 ResourceOracles.
+ * The lifetime of the {@link PathPrefixSet} pins the life time of the associated + * {@link ZipFileSnapshot}; this is because the {@link PathPrefixSet} is referenced from module, + * and {@link ZipFileSnapshot} is not referenced anywhere outside of {@link ZipFileClassPathEntry}
+   * . When the module dies, the {@link ZipFileSnapshot} needs to die also.
    */
- private final Map<PathPrefixSet, ZipFileSnapshot> cachedSnapshots = new IdentityHashMap<PathPrefixSet, ZipFileSnapshot>();
+  @SuppressWarnings("unchecked")
+ private final Map<PathPrefixSet, ZipFileSnapshot> cachedSnapshots = new ReferenceIdentityMap(
+      AbstractReferenceMap.WEAK, AbstractReferenceMap.HARD, true);

   private final String location;

   private final ZipFile zipFile;

-  public ZipFileClassPathEntry(File zipFile) throws IOException {
+  private ZipFileClassPathEntry(File zipFile) throws IOException {
     assert zipFile.isAbsolute();
     this.zipFile = new ZipFile(zipFile);
     this.location = zipFile.toURI().toString();
@@ -87,7 +119,7 @@
* Indexes the zip file on-demand, and only once over the life of the process.
    */
   @Override
-  public Map<AbstractResource, PathPrefix> findApplicableResources(
+ public synchronized Map<AbstractResource, PathPrefix> findApplicableResources(
       TreeLogger logger, PathPrefixSet pathPrefixSet) {
     index(logger);
     ZipFileSnapshot snapshot = cachedSnapshots.get(pathPrefixSet);
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java Wed Aug 4 09:54:49 2010 +++ /trunk/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java Wed Mar 23 12:56:08 2011
@@ -193,12 +193,12 @@
   protected ClassPathEntry getClassPathEntry1AsJar() throws IOException,
       URISyntaxException {
File file = findFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
-    return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(file));
+    return new ExcludeSvnClassPathEntry(ZipFileClassPathEntry.get(file));
   }

protected ClassPathEntry getClassPathEntry1AsZip() throws IOException, URISyntaxException { File file = findFile("com/google/gwt/dev/resource/impl/testdata/cpe1.zip");
-    return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(file));
+    return new ExcludeSvnClassPathEntry(ZipFileClassPathEntry.get(file));
   }

   protected ClassPathEntry getClassPathEntry1AsMock() {
@@ -214,12 +214,12 @@
protected ClassPathEntry getClassPathEntry2AsJar() throws URISyntaxException,
       IOException {
File file = findFile("com/google/gwt/dev/resource/impl/testdata/cpe2.jar");
-    return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(file));
+    return new ExcludeSvnClassPathEntry(ZipFileClassPathEntry.get(file));
   }

protected ClassPathEntry getClassPathEntry2AsZip() throws URISyntaxException, IOException { File file = findFile("com/google/gwt/dev/resource/impl/testdata/cpe2.zip");
-    return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(file));
+    return new ExcludeSvnClassPathEntry(ZipFileClassPathEntry.get(file));
   }

   protected ClassPathEntry getClassPathEntry2AsMock() {
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java Fri Sep 17 13:02:11 2010 +++ /trunk/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java Wed Mar 23 12:56:08 2011
@@ -193,7 +193,7 @@
       URISyntaxException {
     TreeLogger logger = createTestTreeLogger();
File jarFile = findFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
-    ClassPathEntry cpe1jar = new ZipFileClassPathEntry(jarFile);
+    ClassPathEntry cpe1jar = ZipFileClassPathEntry.get(jarFile);

     // test basic caching
     PathPrefixSet pps1 = new PathPrefixSet();

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

Reply via email to