Cache parent artifact resolution

This commit is contained in:
Guillaume Nodet 2024-04-02 15:07:01 +02:00
parent 97518b5b29
commit 8418fb3960
5 changed files with 72 additions and 2 deletions

View File

@ -304,6 +304,7 @@ under the License.
<!-- END default constructor on Plexus/JSR 330 components -->
<!-- system property with that name no longer evaluated -->
<exclude>org.apache.maven.project.DefaultProjectBuilder#DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY</exclude>
<exclude>org.apache.maven.project.ProjectModelResolver#ProjectModelResolver(org.eclipse.aether.RepositorySystemSession,org.eclipse.aether.RequestTrace,org.eclipse.aether.RepositorySystem,org.eclipse.aether.impl.RemoteRepositoryManager,java.util.List,org.apache.maven.project.ProjectBuildingRequest$RepositoryMerging,org.apache.maven.project.ReactorModelPool):CONSTRUCTOR_REMOVED</exclude>
<!-- was only a workaround for Plexus Container, hopefully never used by anyone else -->
<exclude>org.apache.maven.plugin.DefaultBuildPluginManager#setMojoExecutionListeners(java.util.List)</exclude>
<!-- could have never been used due to usage of non-export class (CoreExportsProvider) -->

View File

@ -208,6 +208,7 @@ public List<Profile> getActiveProfilesV4(
remoteRepositoryManager,
project.getRemoteProjectRepositories(),
ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT,
null,
null));
request.setTransformerContextBuilder(modelBuilder.newTransformerContextBuilder());
request.setSystemProperties(toProperties(session.getSystemProperties()));

View File

@ -206,6 +206,7 @@ class BuildSession implements AutoCloseable {
private final RepositorySystemSession session;
private final List<RemoteRepository> repositories;
private final ReactorModelPool modelPool;
private final ConcurrentMap<String, Object> parentCache;
private final TransformerContextBuilder transformerContextBuilder;
private final ExecutorService executor;
@ -222,6 +223,7 @@ class BuildSession implements AutoCloseable {
this.modelPool = null;
this.transformerContextBuilder = null;
}
this.parentCache = new ConcurrentHashMap<>();
}
ExecutorService createExecutor(int parallelism) {
@ -893,7 +895,8 @@ private ModelBuildingRequest getModelBuildingRequest() {
repositoryManager,
repositories,
request.getRepositoryMerging(),
modelPool);
modelPool,
parentCache);
modelBuildingRequest.setValidationLevel(request.getValidationLevel());
modelBuildingRequest.setProcessPlugins(request.isProcessPlugins());

View File

@ -23,7 +23,11 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.maven.api.model.Dependency;
@ -57,6 +61,8 @@
*/
public class ProjectModelResolver implements ModelResolver {
private static final int MAX_CAP = 0x7fff;
private final RepositorySystemSession session;
private final RequestTrace trace;
@ -79,6 +85,8 @@ public class ProjectModelResolver implements ModelResolver {
private final ProjectBuildingRequest.RepositoryMerging repositoryMerging;
private final Map<String, ForkJoinTask<Result>> parentCache;
public ProjectModelResolver(
RepositorySystemSession session,
RequestTrace trace,
@ -86,7 +94,8 @@ public ProjectModelResolver(
RemoteRepositoryManager remoteRepositoryManager,
List<RemoteRepository> repositories,
ProjectBuildingRequest.RepositoryMerging repositoryMerging,
ReactorModelPool modelPool) {
ReactorModelPool modelPool,
Map<String, Object> parentCache) {
this.session = session;
this.trace = trace;
this.resolver = resolver;
@ -98,6 +107,7 @@ public ProjectModelResolver(
this.repositoryMerging = repositoryMerging;
this.repositoryIds = new HashSet<>();
this.modelPool = modelPool;
this.parentCache = parentCache != null ? (Map) parentCache : new ConcurrentHashMap<>();
}
private ProjectModelResolver(ProjectModelResolver original) {
@ -111,6 +121,7 @@ private ProjectModelResolver(ProjectModelResolver original) {
this.repositoryMerging = original.repositoryMerging;
this.repositoryIds = new HashSet<>(original.repositoryIds);
this.modelPool = original.modelPool;
this.parentCache = original.parentCache;
}
public void addRepository(Repository repository) throws InvalidRepositoryException {
@ -171,9 +182,62 @@ public ModelSource resolveModel(String groupId, String artifactId, String versio
return new ArtifactModelSource(pomArtifact.getFile(), groupId, artifactId, version);
}
record Result(ModelSource source, Parent parent, Exception e) {}
private ForkJoinPool pool = new ForkJoinPool(MAX_CAP);
@Override
public ModelSource resolveModel(final Parent parent, AtomicReference<Parent> modified)
throws UnresolvableModelException {
Result result;
try {
ForkJoinTask<Result> future = parentCache.computeIfAbsent(parent.getId(), id -> new ForkJoinTask<>() {
Result result;
@Override
public Result getRawResult() {
return result;
}
@Override
protected void setRawResult(Result result) {
this.result = result;
}
@Override
protected boolean exec() {
try {
AtomicReference<Parent> modified = new AtomicReference<>();
ModelSource source = doResolveModel(parent, modified);
result = new Result(source, modified.get(), null);
} catch (Exception e) {
result = new Result(null, null, e);
}
return true;
}
});
pool.execute(future);
result = future.get();
} catch (Exception e) {
throw new UnresolvableModelException(e, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
}
if (result.e != null) {
uncheckedThrow(result.e);
return null;
} else {
if (result.parent != null && modified != null) {
modified.set(result.parent);
}
return result.source;
}
}
static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
throw (T) t; // rely on vacuous cast
}
private ModelSource doResolveModel(Parent parent, AtomicReference<Parent> modified)
throws UnresolvableModelException {
try {
final Artifact artifact =
new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());

View File

@ -200,6 +200,7 @@ private ModelResolver newModelResolver() throws Exception {
getContainer().lookup(RemoteRepositoryManager.class),
this.getRemoteRepositories(),
ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT,
null,
null);
}