8220633: Optimize CacheFSInfo
authorcushon
Tue, 26 Mar 2019 15:36:19 -0700
changeset 54296 dc66ada06693
parent 54295 49c4b23d8d0a
child 54297 f98f158c1db8
8220633: Optimize CacheFSInfo Reviewed-by: jjg
src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java	Tue Mar 26 15:53:36 2019 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java	Tue Mar 26 15:36:19 2019 -0700
@@ -26,9 +26,11 @@
 package com.sun.tools.javac.file;
 
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.List;
-import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 
 import com.sun.tools.javac.util.Context;
@@ -44,6 +46,12 @@
  */
 public class CacheFSInfo extends FSInfo {
 
+    protected final ConcurrentHashMap<Path, Path> canonicalPathCache = new ConcurrentHashMap<>();
+    protected final ConcurrentHashMap<Path, Optional<BasicFileAttributes>> attributeCache =
+            new ConcurrentHashMap<>();
+    protected final ConcurrentHashMap<Path, List<Path>> jarClassPathCache =
+            new ConcurrentHashMap<>();
+
     /**
      * Register a Context.Factory to create a CacheFSInfo.
      */
@@ -56,68 +64,53 @@
     }
 
     public void clearCache() {
-        cache.clear();
+        canonicalPathCache.clear();
+        attributeCache.clear();
+        jarClassPathCache.clear();
     }
 
     @Override
     public Path getCanonicalFile(Path file) {
-        Entry e = getEntry(file);
-        return e.canonicalFile;
+        return canonicalPathCache.computeIfAbsent(file, super::getCanonicalFile);
     }
 
     @Override
     public boolean exists(Path file) {
-        Entry e = getEntry(file);
-        return e.exists;
+        return getAttributes(file).isPresent();
     }
 
     @Override
     public boolean isDirectory(Path file) {
-        Entry e = getEntry(file);
-        return e.isDirectory;
+        return getAttributes(file).map(BasicFileAttributes::isDirectory).orElse(false);
     }
 
     @Override
     public boolean isFile(Path file) {
-        Entry e = getEntry(file);
-        return e.isFile;
+        return getAttributes(file).map(BasicFileAttributes::isRegularFile).orElse(false);
     }
 
     @Override
     public List<Path> getJarClassPath(Path 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;
+        synchronized (jarClassPathCache) {
+            List<Path> jarClassPath = jarClassPathCache.get(file);
+            if (jarClassPath == null) {
+                jarClassPath = super.getJarClassPath(file);
+                jarClassPathCache.put(file, jarClassPath);
+            }
+            return jarClassPath;
+        }
     }
 
-    private Entry getEntry(Path 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;
+    protected Optional<BasicFileAttributes> getAttributes(Path file) {
+        return attributeCache.computeIfAbsent(file, this::maybeReadAttributes);
     }
 
-    // could also be a Map<File,SoftReference<Entry>> ?
-    private final Map<Path,Entry> cache = new ConcurrentHashMap<>();
-
-    private static class Entry {
-        Path canonicalFile;
-        boolean exists;
-        boolean isFile;
-        boolean isDirectory;
-        List<Path> jarClassPath;
+    protected Optional<BasicFileAttributes> maybeReadAttributes(Path file) {
+        try {
+            return Optional.of(Files.readAttributes(file, BasicFileAttributes.class));
+        } catch (IOException e) {
+            // Ignore; means file not found
+            return Optional.empty();
+        }
     }
 }