Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Fedorenko2013-06-15 11:23:33 +0000
committerIgor Fedorenko2013-06-16 17:02:25 +0000
commit2ced6bdd4fdec5faa8864fda4c3c6596c2055c4a (patch)
tree16c9d7440c61ed11aa52f28b048f324e80307e52
parent561d6fbfd7c132dcdc29f4bd610aa2a590c498c7 (diff)
downloadm2e-core-2ced6bdd4fdec5faa8864fda4c3c6596c2055c4a.tar.gz
m2e-core-2ced6bdd4fdec5faa8864fda4c3c6596c2055c4a.tar.xz
m2e-core-2ced6bdd4fdec5faa8864fda4c3c6596c2055c4a.zip
Reintroduced small MavenProject instances cache
MavenProject instances cache size is hardcoded to 5 and it is meant to improve incremental build performance. From limited and not very scientific testing, trivial m2e-maven-runtime incremental build takes ~130ms without the cache and <30ms with the cache. Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
-rw-r--r--m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml3
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java138
2 files changed, 106 insertions, 35 deletions
diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml
index 9cb34edb..82e07f97 100644
--- a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml
+++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml
@@ -30,7 +30,7 @@
<sisu.version>2.3.0</sisu.version>
<aether.version>1.13.1</aether.version>
- <guava.version>10.0.1</guava.version>
+ <guava.version>11.0.2</guava.version>
<!-- below are m2e-specific addons -->
<plexus-build-api.version>0.0.7</plexus-build-api.version>
@@ -200,6 +200,7 @@
org.sonatype.plexus.*,
org.sonatype.aether.*,
com.google.inject.*,
+ com.google.common.*,
javax.inject.*,
org.sonatype.maven.wagon.*,
</_exportcontents>
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java
index 320f1c33..68070024 100644
--- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java
@@ -26,10 +26,18 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
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.RemovalCause;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -140,6 +148,8 @@ public class ProjectRegistryManager {
*/
private final Map<MavenProjectFacade, MavenProject> legacyMavenProjects = new IdentityHashMap<MavenProjectFacade, MavenProject>();
+ private final Cache<MavenProjectFacade, MavenProject> mavenProjectCache;
+
public ProjectRegistryManager(MavenImpl maven, File stateLocationDir, boolean readState,
IMavenMarkerManager mavenMarkerManager) {
this.markerManager = mavenMarkerManager;
@@ -149,6 +159,8 @@ public class ProjectRegistryManager {
ProjectRegistry state = readState && stateReader != null ? stateReader.readWorkspaceState(this) : null;
this.projectRegistry = (state != null && state.isValid()) ? state : new ProjectRegistry();
+
+ this.mavenProjectCache = createProjectCache();
}
/**
@@ -246,27 +258,6 @@ public class ProjectRegistryManager {
return pomSet;
}
- private void flushCaches(IFile pom, MavenProjectFacade facade) {
- ArtifactKey key = null;
- MavenProject project = null;
-
- if(facade != null) {
- key = facade.getArtifactKey();
- project = getMavenProject(facade); // cached only
- }
- try {
- IManagedCache cache = (IManagedCache) maven.getPlexusContainer().lookup(MavenMetadataCache.class);
- cache.removeProject(pom, key);
- } catch(ComponentLookupException ex) {
- // can't really happen
- } catch(CoreException ex) {
- // can't really happen
- }
- if(project != null) {
- ((MavenImpl) getMaven()).releaseExtensionsRealm(project);
- }
- }
-
/**
* @deprecated this method does not properly join {@link IMavenExecutionContext}, use
* {@link #refresh(Set, IProgressMonitor)} instead.
@@ -762,9 +753,19 @@ public class ProjectRegistryManager {
return projectRegistry.getProjectFacade(groupId, artifactId, version);
}
- MavenExecutionResult readProjectWithDependencies(IFile pomFile, ResolverConfiguration resolverConfiguration,
- IProgressMonitor monitor) {
- return readProjectWithDependencies(projectRegistry, pomFile, resolverConfiguration, monitor);
+ MavenProject readProjectWithDependencies(IFile pomFile, ResolverConfiguration resolverConfiguration,
+ IProgressMonitor monitor) throws CoreException {
+ MavenExecutionResult result = readProjectWithDependencies(projectRegistry, pomFile, resolverConfiguration, monitor);
+ MavenProject mavenProject = result.getProject();
+ if(mavenProject != null) {
+ return mavenProject;
+ }
+ MultiStatus status = new MultiStatus(IMavenConstants.PLUGIN_ID, 0, Messages.MavenProjectFacade_error, null);
+ List<Throwable> exceptions = result.getExceptions();
+ for(Throwable e : exceptions) {
+ status.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, 0, e.getMessage(), e));
+ }
+ throw new CoreException(status);
}
private MavenExecutionResult readProjectWithDependencies(IProjectRegistry state, final IFile pomFile,
@@ -924,7 +925,21 @@ public class ProjectRegistryManager {
return createExecutionContext(projectRegistry, pom, resolverConfiguration);
}
- MavenProject getMavenProject(MavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
+ /**
+ * There are three MavenProjectFacade-to-MavenProject maps.
+ * <ul>
+ * <li>Each MavenExecutionContext has "context project map" that guarantees consistent facade-project association for
+ * entire lifespan of the context. In other words, calling facade.getMavenProject multiple times from within the same
+ * maven execution scope is guaranteed to return the same MavenProject instance.</li>
+ * <li>Global "project cache", that is meant to improve performance during incremental workspace builds. The project
+ * cache is small and cached values are discarded and reloaded as needed.</li>
+ * <li>Global "legacy support project map" provides support for legacy, i.e. pre m2e 1.4, extensions that setup
+ * MojoExecution instances outside of maven execution scope. Legacy support project map entries are not discarded
+ * until their corresponding facade instances are discarded.</li>
+ * </ul>
+ */
+
+ MavenProject getMavenProject(final MavenProjectFacade facade, final IProgressMonitor monitor) throws CoreException {
MavenProject mavenProject;
synchronized(legacyMavenProjects) {
mavenProject = legacyMavenProjects.get(facade);
@@ -935,16 +950,18 @@ public class ProjectRegistryManager {
Map<MavenProjectFacade, MavenProject> mavenProjects = getContextProjects();
mavenProject = mavenProjects.get(facade);
if(mavenProject == null) {
- MavenExecutionResult result = readProjectWithDependencies(facade.getPom(), facade.getResolverConfiguration(),
- monitor);
- mavenProject = result.getProject();
- if(mavenProject == null) {
- MultiStatus status = new MultiStatus(IMavenConstants.PLUGIN_ID, 0, Messages.MavenProjectFacade_error, null);
- List<Throwable> exceptions = result.getExceptions();
- for(Throwable e : exceptions) {
- status.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, 0, e.getMessage(), e));
+ try {
+ mavenProject = mavenProjectCache.get(facade, new Callable<MavenProject>() {
+ public MavenProject call() throws Exception {
+ return readProjectWithDependencies(facade.getPom(), facade.getResolverConfiguration(), monitor);
+ }
+ });
+ } catch(ExecutionException ex) {
+ Throwable cause = ex.getCause();
+ if(cause instanceof CoreException) {
+ throw (CoreException) cause;
}
- throw new CoreException(status);
+ throw new RuntimeException(cause); // this really should never happen
}
mavenProjects.put(facade, mavenProject);
}
@@ -957,6 +974,12 @@ public class ProjectRegistryManager {
mavenProject = legacyMavenProjects.get(facade);
}
if(mavenProject == null) {
+ mavenProject = mavenProjectCache.getIfPresent(facade);
+ if(mavenProject != null) {
+ putMavenProject(facade, mavenProject);
+ }
+ }
+ if(mavenProject == null) {
mavenProject = getContextProjects().get(facade);
}
return mavenProject;
@@ -992,4 +1015,51 @@ public class ProjectRegistryManager {
}
return projects;
}
+
+ private Cache<MavenProjectFacade, MavenProject> createProjectCache() {
+ final RemovalListener<MavenProjectFacade, MavenProject> removalListener = new RemovalListener<MavenProjectFacade, MavenProject>() {
+ public void onRemoval(RemovalNotification<MavenProjectFacade, MavenProject> notification) {
+ if(notification.getCause() == RemovalCause.SIZE || notification.getCause() == RemovalCause.REPLACED) {
+ // 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
+ final MavenProjectFacade facade = notification.getKey();
+ final MavenProject mavenProject = notification.getValue();
+ final Map<MavenProjectFacade, MavenProject> contextProjects = getContextProjects();
+ if(contextProjects != null && !contextProjects.containsKey(facade)) {
+ flushMavenCaches(facade.getPom(), facade.getArtifactKey(), mavenProject);
+ }
+ }
+ }
+ };
+ return CacheBuilder.newBuilder().maximumSize(5).removalListener(removalListener).build();
+ }
+
+ private void flushCaches(IFile pom, MavenProjectFacade facade) {
+ ArtifactKey key = null;
+ MavenProject project = null;
+
+ if(facade != null) {
+ key = facade.getArtifactKey();
+ project = getMavenProject(facade); // cached only
+ mavenProjectCache.invalidate(facade);
+ }
+ flushMavenCaches(pom, key, project);
+ }
+
+ /**
+ * Flushes caches maintained by Maven core.
+ */
+ void flushMavenCaches(IFile pom, ArtifactKey key, MavenProject project) {
+ try {
+ IManagedCache cache = (IManagedCache) maven.getPlexusContainer().lookup(MavenMetadataCache.class);
+ cache.removeProject(pom, key);
+ } catch(ComponentLookupException ex) {
+ // can't really happen
+ } catch(CoreException ex) {
+ // can't really happen
+ }
+ if(project != null) {
+ ((MavenImpl) getMaven()).releaseExtensionsRealm(project);
+ }
+ }
}

Back to the top