Skip to content

Commit

Permalink
Improve performance of MCPath by caching calls to find(String), simil…
Browse files Browse the repository at this point in the history
…arly to find(String, String). Use replace instead of replaceAll where possible.
  • Loading branch information
Hellwig-SE committed Nov 5, 2024
1 parent bf05929 commit 27d89ad
Showing 1 changed file with 34 additions and 15 deletions.
49 changes: 34 additions & 15 deletions monticore-runtime/src/main/java/de/monticore/io/paths/MCPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import org.apache.commons.io.filefilter.RegexFileFilter;

import javax.annotation.Nonnull;
import java.io.*;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
Expand Down Expand Up @@ -91,6 +93,14 @@ public Optional<URL> load(@Nonnull FindCacheKey key) {
}
});

final LoadingCache<String, List<URL>> resolvedUrlsCache = CacheBuilder.newBuilder()
.build(new CacheLoader<>() {
@Override
public List<URL> load(String key) {
return do_findResolvedUrls(key);
}
});

/**
* Method for calculating a list of files located in an entry of the passed model path,
* with the passed qualified model name, and the passed regular expression over the file extension.
Expand Down Expand Up @@ -156,7 +166,7 @@ Optional<URL> do_find(FindCacheKey k) {
// iterate MCPath entries and check whether folder path exists within these
for (Path p : getEntries()) {
if(p.toString().endsWith(".jar")){
String path = "/" + folderPath.replaceAll("\\\\", "/") + "/" + fileNameRegEx;
String path = "/" + folderPath.replace('\\', '/') + "/" + fileNameRegEx;
if (k.fileExtRegEx.equals(".*sym")) {
// For .jar entries with a *.sym file extension regex, we cache the jar entries
jarSymCache.getUnchecked(p).getCandidates(path).map(uri -> {
Expand All @@ -180,7 +190,7 @@ Optional<URL> do_find(FindCacheKey k) {
}
}
File folder = p.resolve(folderPath).toFile(); //e.g., "src/test/resources/foo/bar"
if (folder.exists() && folder.isDirectory()) {
if (folder.isDirectory()) {
// perform the actual file filter on the folder and collect result
Arrays.stream(folder.listFiles(filter))
.map(f -> toURL(folder.toPath().resolve(f.getName())))
Expand Down Expand Up @@ -210,14 +220,8 @@ else if (1 < resolvedURLs.size()) {
* matching models
*/
public Optional<URL> find(String path) {
String fixedPath = path.replaceAll("\\" + File.separator, "/");

List<URL> resolvedURLs = classloaderMap.keySet().stream()
.map(classloader -> FileReaderWriter.getResource(classloader, fixedPath))
.filter(Optional::isPresent)
.map(Optional::get)
.distinct()
.collect(Collectors.toList());
String fixedPath = path.replace(File.separatorChar, '/');
List<URL> resolvedURLs = findResolvedUrls(fixedPath);

if (1 == resolvedURLs.size()) {
File resolvedFile = new File(resolvedURLs.get(0).getFile());
Expand All @@ -237,6 +241,19 @@ else if (1 < resolvedURLs.size()) {
return Optional.empty();
}

protected List<URL> findResolvedUrls(String fixedPath){
return resolvedUrlsCache.getUnchecked(fixedPath);
}

protected List<URL> do_findResolvedUrls(String fixedPath) {
return classloaderMap.keySet().stream()
.map(classloader -> FileReaderWriter.getResource(classloader, fixedPath))
.filter(Optional::isPresent)
.map(Optional::get)
.distinct()
.collect(Collectors.toList());
}

@Override
public String toString() {
String result = "[";
Expand Down Expand Up @@ -295,6 +312,7 @@ public void close(){
void invalidateCaches() {
jarSymCache.invalidateAll();
findCache.invalidateAll();
resolvedUrlsCache.invalidateAll();
}

// A List of all file systems opened for jars.
Expand Down Expand Up @@ -370,18 +388,19 @@ static class CachedPath {
final Set<Path> absolutePaths = new HashSet<>();
// path of the filesystem, which will be removed in the filter
final String replacedFS;
final Pattern removeFsPattern;

public CachedPath(String replacedFS) {
this.replacedFS = replacedFS;
this.replacedFS = replacedFS.replace('\\', '/');
removeFsPattern = Pattern.compile(Pattern.quote(replacedFS));
}

/**
* @param path the path regex, see {@link GlobExpressionEvaluator}
* @return a stream of URIs matching against this path
*/
Stream<URI> getCandidates(String path) {
path = path.replaceAll(Pattern.quote(replacedFS.replaceAll("\\\\", "/")), "");

path = removeFsPattern.matcher(path).replaceAll("");
Pattern pattern = Pattern.compile(path);

return absolutePaths.stream().filter(p -> pattern.matcher(p.toString()).matches()).map(this::toURL);
Expand All @@ -391,7 +410,7 @@ URI toURL(Path path) {
URI uri = path.toUri();
// this takes care of white spaces in files, especially jars, if they are double encoded
if (uri.toString().contains("%2520")) {
uri = URI.create(uri.toString().replaceAll("%2520", "%20"));
uri = URI.create(uri.toString().replace("%2520", "%20"));
}
return uri;
}
Expand Down

0 comments on commit 27d89ad

Please sign in to comment.