Skip to content

Optimize resource lookup in DevTools restart #46289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,13 @@ public Resource[] getResources(String locationPattern) throws IOException {
private List<Resource> getAdditionalResources(String locationPattern) throws MalformedURLException {
List<Resource> additionalResources = new ArrayList<>();
String trimmedLocationPattern = trimLocationPattern(locationPattern);
for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
String name = entry.getKey();
ClassLoaderFile file = entry.getValue();
if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {
URL url = new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
UrlResource resource = new UrlResource(url);
additionalResources.add(resource);
}
for (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {
String name = entry.getKey();
ClassLoaderFile file = entry.getValue();
if (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {
URL url = new URL("reloaded", null, -1, "/" + name, new ClassLoaderFileURLStreamHandler(file));
UrlResource resource = new UrlResource(url);
additionalResources.add(resource);
}
}
return additionalResources;
Expand All @@ -147,20 +145,18 @@ private String trimLocationPattern(String pattern) {
}

private boolean isDeleted(Resource resource) {
for (SourceDirectory sourceDirectory : this.classLoaderFiles.getSourceDirectories()) {
for (Entry<String, ClassLoaderFile> entry : sourceDirectory.getFilesEntrySet()) {
try {
String name = entry.getKey();
ClassLoaderFile file = entry.getValue();
if (file.getKind() == Kind.DELETED && resource.exists()
&& resource.getURI().toString().endsWith(name)) {
return true;
}
}
catch (IOException ex) {
throw new IllegalStateException("Failed to retrieve URI from '" + resource + "'", ex);
for (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {
try {
String name = entry.getKey();
ClassLoaderFile file = entry.getValue();
if (file.getKind() == Kind.DELETED && resource.exists()
&& resource.getURI().toString().endsWith(name)) {
return true;
}
}
catch (IOException ex) {
throw new IllegalStateException("Failed to retrieve URI from '" + resource + "'", ex);
}
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,18 @@ public class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable

private final Map<String, SourceDirectory> sourceDirectories;

/**
* A flattened map of all files from all source directories for fast, O(1) lookups.
* The key is the file's relative path, and the value is the ClassLoaderFile.
*/
private final Map<String, ClassLoaderFile> filesByName;

/**
* Create a new {@link ClassLoaderFiles} instance.
*/
public ClassLoaderFiles() {
this.sourceDirectories = new LinkedHashMap<>();
this.filesByName = new LinkedHashMap<>();
}

/**
Expand All @@ -57,6 +64,7 @@ public ClassLoaderFiles() {
public ClassLoaderFiles(ClassLoaderFiles classLoaderFiles) {
Assert.notNull(classLoaderFiles, "'classLoaderFiles' must not be null");
this.sourceDirectories = new LinkedHashMap<>(classLoaderFiles.sourceDirectories);
this.filesByName = new LinkedHashMap<>(classLoaderFiles.filesByName);
}

/**
Expand Down Expand Up @@ -94,12 +102,14 @@ public void addFile(String sourceDirectory, String name, ClassLoaderFile file) {
Assert.notNull(file, "'file' must not be null");
removeAll(name);
getOrCreateSourceDirectory(sourceDirectory).add(name, file);
this.filesByName.put(name, file);
}

private void removeAll(String name) {
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
sourceDirectory.remove(name);
}
this.filesByName.remove(name);
}

/**
Expand All @@ -125,22 +135,21 @@ public Collection<SourceDirectory> getSourceDirectories() {
* @return the size of the collection
*/
public int size() {
int size = 0;
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
size += sourceDirectory.getFiles().size();
}
return size;
return this.filesByName.size();
}

@Override
public ClassLoaderFile getFile(String name) {
for (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {
ClassLoaderFile file = sourceDirectory.get(name);
if (file != null) {
return file;
}
}
return null;
return this.filesByName.get(name);
}

/**
* Returns a set of all file entries across all source directories for efficient
* iteration.
* @return a set of all file entries
*/
public Set<Entry<String, ClassLoaderFile>> getFileEntries() {
return Collections.unmodifiableSet(this.filesByName.entrySet());
}

/**
Expand Down