Skip to content

Commit 621450d

Browse files
committed
Cache list-files operations
1 parent 3598091 commit 621450d

2 files changed

Lines changed: 71 additions & 4 deletions

File tree

src/main/java/org/javacs/HideModuleInfo.java renamed to src/main/java/org/javacs/FileManagerWrapper.java

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,25 @@
44
import java.io.File;
55
import java.io.IOException;
66
import java.nio.file.Path;
7+
import java.util.ArrayList;
78
import java.util.Collection;
9+
import java.util.Collections;
10+
import java.util.HashMap;
811
import java.util.Iterator;
12+
import java.util.List;
13+
import java.util.Map;
14+
import java.util.Objects;
915
import java.util.ServiceLoader;
1016
import java.util.Set;
1117
import javax.tools.FileObject;
1218
import javax.tools.JavaFileObject;
1319
import javax.tools.StandardJavaFileManager;
20+
import javax.tools.StandardLocation;
1421

15-
class HideModuleInfo implements StandardJavaFileManager {
22+
class FileManagerWrapper implements StandardJavaFileManager {
1623
private final StandardJavaFileManager delegate;
1724

18-
HideModuleInfo(StandardJavaFileManager delegate) {
25+
FileManagerWrapper(StandardJavaFileManager delegate) {
1926
this.delegate = delegate;
2027
}
2128

@@ -135,10 +142,70 @@ public ClassLoader getClassLoader(Location location) {
135142
return delegate.getClassLoader(location);
136143
}
137144

145+
// Cache calls to list(...)
146+
static class Key {
147+
final Location location;
148+
final String packageName;
149+
final JavaFileObject.Kind kind;
150+
final boolean recurse;
151+
152+
Key(Location location, String packageName, JavaFileObject.Kind kind, boolean recurse) {
153+
this.location = location;
154+
this.packageName = packageName;
155+
this.kind = kind;
156+
this.recurse = recurse;
157+
}
158+
159+
@Override
160+
public boolean equals(Object candidate) {
161+
if (!(candidate instanceof Key)) return false;
162+
var that = (Key) candidate;
163+
164+
return Objects.equals(this.location, that.location)
165+
&& Objects.equals(this.packageName, that.packageName)
166+
&& Objects.equals(this.kind, that.kind)
167+
&& Objects.equals(this.recurse, that.recurse);
168+
}
169+
170+
@Override
171+
public int hashCode() {
172+
return Objects.hash(location, packageName, kind, recurse);
173+
}
174+
}
175+
176+
// Store previous calls to list, because listing directories and .jar files is expensive
177+
private Map<Key, List<JavaFileObject>> cache = new HashMap<>();
178+
179+
private List<JavaFileObject> loadCache(Key key) {
180+
try {
181+
var list = new ArrayList<JavaFileObject>();
182+
var it =
183+
removeModuleInfoInvariant(
184+
delegate.list(key.location, key.packageName, Collections.singleton(key.kind), key.recurse));
185+
for (var file : it) list.add(file);
186+
return list;
187+
} catch (IOException e) {
188+
throw new RuntimeException(e);
189+
}
190+
}
191+
138192
@Override
139193
public Iterable<JavaFileObject> list(
140194
Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
141-
return removeModuleInfoInvariant(delegate.list(location, packageName, kinds, recurse));
195+
// If search source path, skip cache
196+
// TODO does this actually do anything?
197+
if (location == StandardLocation.SOURCE_PATH
198+
|| location == StandardLocation.MODULE_SOURCE_PATH
199+
|| location == StandardLocation.SOURCE_OUTPUT)
200+
return removeModuleInfoInvariant(delegate.list(location, packageName, kinds, recurse));
201+
202+
// Search for each kind separately to improve cacheability
203+
var result = new ArrayList<JavaFileObject>();
204+
for (var kind : kinds) {
205+
var list = cache.computeIfAbsent(new Key(location, packageName, kind, recurse), this::loadCache);
206+
result.addAll(list);
207+
}
208+
return result;
142209
}
143210

144211
@Override

‎src/main/java/org/javacs/JavaCompilerService.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class JavaCompilerService {
3535
private final List<Diagnostic<? extends JavaFileObject>> diags = new ArrayList<>();
3636
// Use the same file manager for multiple tasks, so we don't repeatedly re-compile the same files
3737
private final StandardJavaFileManager fileManager =
38-
new HideModuleInfo(compiler.getStandardFileManager(diags::add, null, Charset.defaultCharset()));
38+
new FileManagerWrapper(compiler.getStandardFileManager(diags::add, null, Charset.defaultCharset()));
3939
// Cache a single compiled file
4040
// Since the user can only edit one file at a time, this should be sufficient
4141
private Cache cache;

0 commit comments

Comments
 (0)