6743107: clean up use of static caches in file manager
authorjjg
Wed, 03 Sep 2008 10:46:25 -0700
changeset 1208 5072b0dd3d52
parent 1206 3a05355982a9
child 1209 add7eef3ce4a
6743107: clean up use of static caches in file manager Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java
langtools/src/share/classes/com/sun/tools/javac/file/FSInfo.java
langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
langtools/src/share/classes/com/sun/tools/javac/file/Paths.java
langtools/src/share/classes/com/sun/tools/javac/main/Main.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java	Wed Sep 03 10:46:25 2008 -0700
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import com.sun.tools.javac.util.Context;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Caching implementation of FSInfo
+ */
+public class CacheFSInfo extends FSInfo {
+
+    /**
+     * Register a Context.Factory to create a singleton CacheFSInfo.
+     */
+    public static void preRegister(final Context context) {
+        context.put(FSInfo.class, new Context.Factory<FSInfo>() {
+            public FSInfo make() {
+                if (singleton == null)
+                    singleton = new CacheFSInfo();
+                context.put(FSInfo.class, singleton);
+                return singleton;
+            }
+        });
+    }
+
+    static CacheFSInfo singleton;
+
+    public void clearCache() {
+        cache.clear();
+    }
+
+    @Override
+    public File getCanonicalFile(File file) {
+        Entry e = getEntry(file);
+        return e.canonicalFile;
+    }
+
+    @Override
+    public boolean exists(File file) {
+        Entry e = getEntry(file);
+        return e.exists;
+    }
+
+    @Override
+    public boolean isDirectory(File file) {
+        Entry e = getEntry(file);
+        return e.isDirectory;
+    }
+
+    @Override
+    public boolean isFile(File file) {
+        Entry e = getEntry(file);
+        return e.isFile;
+    }
+
+    @Override
+    public List<File> getJarClassPath(File file) throws IOException {
+        // don't bother to lock the cache, because it is thread-safe, and
+        // because the worst that can happen would be to create two identical
+        // jar class paths together and have one overwrite the other.
+        Entry e = getEntry(file);
+        if (e.jarClassPath == null)
+            e.jarClassPath = super.getJarClassPath(file);
+        return e.jarClassPath;
+    }
+
+    private Entry getEntry(File file) {
+        // don't bother to lock the cache, because it is thread-safe, and
+        // because the worst that can happen would be to create two identical
+        // entries together and have one overwrite the other.
+        Entry e = cache.get(file);
+        if (e == null) {
+            e = new Entry();
+            e.canonicalFile = super.getCanonicalFile(file);
+            e.exists = super.exists(file);
+            e.isDirectory = super.isDirectory(file);
+            e.isFile = super.isFile(file);
+            cache.put(file, e);
+        }
+        return e;
+    }
+
+    // could also be a Map<File,SoftReference<Entry>> ?
+    private Map<File,Entry> cache = new ConcurrentHashMap<File,Entry>();
+
+    private static class Entry {
+        File canonicalFile;
+        boolean exists;
+        boolean isFile;
+        boolean isDirectory;
+        List<File> jarClassPath;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/FSInfo.java	Wed Sep 03 10:46:25 2008 -0700
@@ -0,0 +1,89 @@
+
+package com.sun.tools.javac.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Get meta-info about files. Default direct (non-caching) implementation.
+ * @see CacheFSInfo
+ */
+public class FSInfo {
+
+    /** Get the FSInfo instance for this context.
+     *  @param context the context
+     *  @return the Paths instance for this context
+     */
+    public static FSInfo instance(Context context) {
+        FSInfo instance = context.get(FSInfo.class);
+        if (instance == null)
+            instance = new FSInfo();
+        return instance;
+    }
+
+    protected FSInfo() {
+    }
+
+    protected FSInfo(Context context) {
+        context.put(FSInfo.class, this);
+    }
+
+    public File getCanonicalFile(File file) {
+        try {
+            return file.getCanonicalFile();
+        } catch (IOException e) {
+            return file.getAbsoluteFile();
+        }
+    }
+
+    public boolean exists(File file) {
+        return file.exists();
+    }
+
+    public boolean isDirectory(File file) {
+        return file.isDirectory();
+    }
+
+    public boolean isFile(File file) {
+        return file.isFile();
+    }
+
+    public List<File> getJarClassPath(File file) throws IOException {
+        String parent = file.getParent();
+        JarFile jarFile = new JarFile(file);
+        try {
+            Manifest man = jarFile.getManifest();
+            if (man == null)
+                return Collections.emptyList();
+
+            Attributes attr = man.getMainAttributes();
+            if (attr == null)
+                return Collections.emptyList();
+
+            String path = attr.getValue(Attributes.Name.CLASS_PATH);
+            if (path == null)
+                return Collections.emptyList();
+
+            List<File> list = new ArrayList<File>();
+
+            for (StringTokenizer st = new StringTokenizer(path); st.hasMoreTokens(); ) {
+                String elt = st.nextToken();
+                File f = (parent == null ? new File(elt) : new File(parent, elt));
+                list.add(f);
+            }
+
+            return list;
+        } finally {
+            jarFile.close();
+        }
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Aug 29 11:10:12 2008 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Wed Sep 03 10:46:25 2008 -0700
@@ -55,7 +55,6 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.zip.ZipFile;
 
 import javax.lang.model.SourceVersion;
@@ -88,10 +87,6 @@
 
     boolean useZipFileIndex;
 
-    private static boolean CHECK_ZIP_TIMESTAMP = false;
-    private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>();
-
-
     public static char[] toArray(CharBuffer buffer) {
         if (buffer.hasArray())
             return ((CharBuffer)buffer.compact().flip()).array();
@@ -110,6 +105,8 @@
 
     private Options options;
 
+    private FSInfo fsInfo;
+
     private final File uninited = new File("U N I N I T E D");
 
     private final Set<JavaFileObject.Kind> sourceOrClass =
@@ -172,9 +169,9 @@
         }
 
         options = Options.instance(context);
+        fsInfo = FSInfo.instance(context);
 
         useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
-        CHECK_ZIP_TIMESTAMP = System.getProperty("checkZipIndexTimestamp") != null;// TODO: options.get("checkZipIndexTimestamp") != null;
 
         mmappedIO = options.get("mmappedIO") != null;
         ignoreSymbolFile = options.get("ignore.symbol.file") != null;
@@ -289,20 +286,7 @@
                                ListBuffer<JavaFileObject> l) {
         Archive archive = archives.get(directory);
 
-        boolean isFile = false;
-        if (CHECK_ZIP_TIMESTAMP) {
-            Boolean isf = isDirectory.get(directory);
-            if (isf == null) {
-                isFile = directory.isFile();
-                isDirectory.put(directory, isFile);
-            }
-            else {
-                isFile = directory.isFile();
-            }
-        }
-        else {
-            isFile = directory.isFile();
-        }
+        boolean isFile = fsInfo.isFile(directory);
 
         if (archive != null || isFile) {
             if (archive == null) {
--- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java	Fri Aug 29 11:10:12 2008 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java	Wed Sep 03 10:46:25 2008 -0700
@@ -31,19 +31,11 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.jar.Attributes;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Iterator;
-import java.util.StringTokenizer;
 import java.util.zip.ZipFile;
-import java.util.ArrayList;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
 import javax.tools.JavaFileManager.Location;
 
 import com.sun.tools.javac.code.Lint;
@@ -90,21 +82,8 @@
     /** Handler for -Xlint options */
     private Lint lint;
 
-    private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
-    private static Map<File, PathEntry> pathExistanceCache = new ConcurrentHashMap<File, PathEntry>();
-    private static Map<File, java.util.List<File>> manifestEntries = new ConcurrentHashMap<File, java.util.List<File>>();
-    private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>();
-    private static Lock lock = new ReentrantLock();
-
-    public static void clearPathExistanceCache() {
-            pathExistanceCache.clear();
-    }
-
-    static class PathEntry {
-        boolean exists = false;
-        boolean isFile = false;
-        File cannonicalPath = null;
-    }
+    /** Access to (possibly cached) file info */
+    private FSInfo fsInfo;
 
     protected Paths(Context context) {
         context.put(pathsKey, this);
@@ -116,6 +95,7 @@
         log = Log.instance(context);
         options = Options.instance(context);
         lint = Lint.instance(context);
+        fsInfo = FSInfo.instance(context);
     }
 
     /** Whether to warn about non-existent path elements */
@@ -294,51 +274,17 @@
         }
 
         public void addFile(File file, boolean warn) {
-            boolean foundInCache = false;
-            PathEntry pe = null;
-            if (!NON_BATCH_MODE) {
-                    pe = pathExistanceCache.get(file);
-                    if (pe != null) {
-                        foundInCache = true;
-                    }
-                    else {
-                        pe = new PathEntry();
-                    }
-            }
-            else {
-                pe = new PathEntry();
-            }
-
-            File canonFile;
-            try {
-                if (!foundInCache) {
-                    pe.cannonicalPath = file.getCanonicalFile();
-                }
-                else {
-                   canonFile = pe.cannonicalPath;
-                }
-            } catch (IOException e) {
-                pe.cannonicalPath = canonFile = file;
-            }
-
-            if (contains(file) || canonicalValues.contains(pe.cannonicalPath)) {
+            File canonFile = fsInfo.getCanonicalFile(file);
+            if (contains(file) || canonicalValues.contains(canonFile)) {
                 /* Discard duplicates and avoid infinite recursion */
                 return;
             }
 
-            if (!foundInCache) {
-                pe.exists = file.exists();
-                pe.isFile = file.isFile();
-                if (!NON_BATCH_MODE) {
-                    pathExistanceCache.put(file, pe);
-                }
-            }
-
-            if (! pe.exists) {
+            if (! fsInfo.exists(file)) {
                 /* No such file or directory exists */
                 if (warn)
                     log.warning("path.element.not.found", file);
-            } else if (pe.isFile) {
+            } else if (fsInfo.isFile(file)) {
                 /* File is an ordinary file. */
                 if (!isArchive(file)) {
                     /* Not a recognized extension; open it to see if
@@ -360,9 +306,9 @@
             /* Now what we have left is either a directory or a file name
                confirming to archive naming convention */
             super.add(file);
-            canonicalValues.add(pe.cannonicalPath);
+            canonicalValues.add(canonFile);
 
-            if (expandJarClassPaths && file.exists() && file.isFile())
+            if (expandJarClassPaths && fsInfo.exists(file) && fsInfo.isFile(file))
                 addJarClassPath(file, warn);
         }
 
@@ -372,58 +318,8 @@
         // filenames, but if we do, we should redo all path-related code.
         private void addJarClassPath(File jarFile, boolean warn) {
             try {
-                java.util.List<File> manifestsList = manifestEntries.get(jarFile);
-                if (!NON_BATCH_MODE) {
-                    lock.lock();
-                    try {
-                        if (manifestsList != null) {
-                            for (File entr : manifestsList) {
-                                addFile(entr, warn);
-                            }
-                            return;
-                        }
-                    }
-                    finally {
-                        lock.unlock();
-                    }
-                }
-
-                if (!NON_BATCH_MODE) {
-                    manifestsList = new ArrayList<File>();
-                    manifestEntries.put(jarFile, manifestsList);
-                }
-
-                String jarParent = jarFile.getParent();
-                JarFile jar = new JarFile(jarFile);
-
-                try {
-                    Manifest man = jar.getManifest();
-                    if (man == null) return;
-
-                    Attributes attr = man.getMainAttributes();
-                    if (attr == null) return;
-
-                    String path = attr.getValue(Attributes.Name.CLASS_PATH);
-                    if (path == null) return;
-
-                    for (StringTokenizer st = new StringTokenizer(path);
-                         st.hasMoreTokens();) {
-                        String elt = st.nextToken();
-                        File f = (jarParent == null ? new File(elt) : new File(jarParent, elt));
-                        addFile(f, warn);
-
-                        if (!NON_BATCH_MODE) {
-                            lock.lock();
-                            try {
-                                manifestsList.add(f);
-                            }
-                            finally {
-                                lock.unlock();
-                            }
-                        }
-                    }
-                } finally {
-                    jar.close();
+                for (File f: fsInfo.getJarClassPath(jarFile)) {
+                    addFile(f, warn);
                 }
             } catch (IOException e) {
                 log.error("error.reading.file", jarFile, e.getLocalizedMessage());
@@ -554,24 +450,9 @@
     }
 
     /** Is this the name of an archive file? */
-    private static boolean isArchive(File file) {
+    private boolean isArchive(File file) {
         String n = file.getName().toLowerCase();
-        boolean isFile = false;
-        if (!NON_BATCH_MODE) {
-            Boolean isf = isDirectory.get(file);
-            if (isf == null) {
-                isFile = file.isFile();
-                isDirectory.put(file, isFile);
-            }
-            else {
-                isFile = isf;
-            }
-        }
-        else {
-            isFile = file.isFile();
-        }
-
-        return isFile
+        return fsInfo.isFile(file)
             && (n.endsWith(".jar") || n.endsWith(".zip"));
     }
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java	Fri Aug 29 11:10:12 2008 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java	Wed Sep 03 10:46:25 2008 -0700
@@ -31,6 +31,7 @@
 import java.util.MissingResourceException;
 
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.file.CacheFSInfo;
 import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.jvm.Target;
 import com.sun.tools.javac.main.JavacOption.Option;
@@ -368,6 +369,12 @@
 
             context.put(Log.outKey, out);
 
+            // allow System property in following line as a Mustang legacy
+            boolean batchMode = (options.get("nonBatchMode") == null
+                        && System.getProperty("nonBatchMode") == null);
+            if (batchMode)
+                CacheFSInfo.preRegister(context);
+
             fileManager = context.get(JavaFileManager.class);
 
             comp = JavaCompiler.instance(context);