Skip to content

Commit

Permalink
Use Guava cache for MavenProjectCache
Browse files Browse the repository at this point in the history
Easier to maintain, and thread safe.
  • Loading branch information
mickaelistria committed Sep 28, 2022
1 parent 8036b13 commit 0b87742
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 26 deletions.
5 changes: 3 additions & 2 deletions org.eclipse.m2e.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.m2e.core;singleton:=true
Bundle-Version: 2.0.3.qualifier
Bundle-Version: 2.0.4.qualifier
Bundle-Activator: org.eclipse.m2e.core.internal.MavenPluginActivator
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Expand Down Expand Up @@ -49,7 +49,8 @@ Export-Package: org.eclipse.m2e.core,
org.eclipse.m2e.core.repository
MavenArtifact-GroupId: org.eclipse.m2e
MavenArtifact-ArtifactId: org.eclipse.m2e.core
Import-Package: javax.inject;version="1.0.0",
Import-Package: com.google.common.cache,
javax.inject;version="1.0.0",
org.slf4j;version="1.6.2"
Automatic-Module-Name: org.eclipse.m2e.core
Service-Component: OSGI-INF/org.eclipse.m2e.core.embedder.MavenModelManager.xml,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Collectors;

Expand All @@ -46,6 +47,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalNotification;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
Expand Down Expand Up @@ -171,7 +176,7 @@ public class ProjectRegistryManager implements ISaveParticipant {

private volatile Thread syncRefreshThread;

private final Map<MavenProjectFacade, MavenProject> mavenProjectCache;
private final Cache<MavenProjectFacade, MavenProject> mavenProjectCache;

/**
* @noreference For tests only
Expand Down Expand Up @@ -1033,8 +1038,14 @@ public IMavenExecutionContext createExecutionContext(IFile pom, ResolverConfigur
MavenProject getMavenProject(MavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
Map<MavenProjectFacade, MavenProject> mavenProjects = getContextProjects();
try {
return mavenProjects.computeIfAbsent(facade, fac -> mavenProjectCache.computeIfAbsent(fac,
f -> readProjectWithDependencies(f.getPom(), f.getResolverConfiguration(), monitor)));
return mavenProjects.computeIfAbsent(facade, fac -> {
try {
return mavenProjectCache.get(fac,
() -> readProjectWithDependencies(fac.getPom(), fac.getResolverConfiguration(), monitor));
} catch(ExecutionException ex) {
throw new RuntimeException(ex);
}
});
} catch(RuntimeException ex) { // thrown by method called in lambda to carry CoreException
Throwable cause = ex.getCause();
if(cause instanceof CoreException coreException) {
Expand All @@ -1045,7 +1056,7 @@ MavenProject getMavenProject(MavenProjectFacade facade, IProgressMonitor monitor
}

MavenProject getMavenProject(MavenProjectFacade facade) {
MavenProject mavenProject = mavenProjectCache.get(facade);
MavenProject mavenProject = mavenProjectCache.getIfPresent(facade);
if(mavenProject != null) {
putMavenProject(facade, mavenProject);
} else {
Expand Down Expand Up @@ -1087,33 +1098,24 @@ private Map<MavenProjectFacade, MavenProject> getContextProjects() {
return new IdentityHashMap<>();
}

private Map<MavenProjectFacade, MavenProject> createProjectCache() {
private Cache<MavenProjectFacade, MavenProject> createProjectCache() {
int maxCacheSize = Integer.getInteger("m2e.project.cache.size", 20);
return Collections.synchronizedMap(new LinkedHashMap<>(maxCacheSize * 4 / 3 + 1, 0.75f, true) {
private static final long serialVersionUID = 8022606648487974598L;

@Override
protected boolean removeEldestEntry(java.util.Map.Entry<MavenProjectFacade, MavenProject> eldest) {
if(size() > maxCacheSize) {
// there is currently no good way to determine if MavenProject instance is still being used or not
// for now assume that cache entries removed from project cache can only be referenced by context map
MavenProjectFacade facade = eldest.getKey();
Map<MavenProjectFacade, MavenProject> contextProjects = getContextProjects();
if(!contextProjects.containsKey(facade)) {
flushMavenCaches(facade.getPomFile(), facade.getArtifactKey(), false);
}
return true;
}
return false;
}
});
return CacheBuilder.newBuilder() //
.maximumSize(maxCacheSize) //
.removalListener((RemovalNotification<MavenProjectFacade, MavenProject> removed) -> {
Map<MavenProjectFacade, MavenProject> contextProjects = getContextProjects();
MavenProjectFacade facade = removed.getKey();
if(!contextProjects.containsKey(facade)) {
flushMavenCaches(facade.getPomFile(), facade.getArtifactKey(), false);
}
}).build();
}

private Set<IFile> flushCaches(MutableProjectRegistry newState, IFile pom, MavenProjectFacade facade,
boolean forceDependencyUpdate) {
if(facade != null) {
ArtifactKey key = facade.getArtifactKey();
mavenProjectCache.remove(facade);
mavenProjectCache.invalidate(facade);
Set<IFile> ifiles = new HashSet<>();
for(File file : flushMavenCaches(facade.getPomFile(), key, forceDependencyUpdate)) {
MavenProjectFacade affected = projectRegistry.getProjectFacade(file);
Expand Down

0 comments on commit 0b87742

Please sign in to comment.