From b6f2f0f3604c97af00b9d539fd647bafd237abbf Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 3 Aug 2026 02:36:30 +0200 Subject: [PATCH] =?UTF-8?q?Cache=20projectsWithDeployExecution=20list=20to?= =?UTF-8?q?=20avoid=20O(N=C2=B2)=20reactor=20scan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeployMojo.allProjectsMarked() calls hasDeployExecution() for every reactor project on every module invocation. hasDeployExecution() calls getPluginsAsMap() for each project, producing O(N²) evaluations in a large reactor build (e.g., 4383² ≈ 19.2M calls in a 4383-module project). Fix: cache the filtered list of projects with deploy executions in the first reactor project's plugin context. The list is invariant during a build. Also simplify allProjectsMarked() to only check the projects that actually have deploy executions, rather than iterating the full reactor and testing the disjunction (hasState || !hasDeployExecution). Co-Authored-By: Claude Opus 4.6 --- .../maven/plugins/deploy/DeployMojo.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java b/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java index 3f0e32d..d95d182 100644 --- a/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java +++ b/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.apache.maven.api.Artifact; import org.apache.maven.api.MojoExecution; @@ -145,6 +146,8 @@ private enum State { TO_BE_DEPLOYED } + private static final String PROJECTS_WITH_DEPLOY_KEY = DeployMojo.class.getName() + ".projectsWithDeploy"; + public DeployMojo() {} private void putState(State state) { @@ -195,7 +198,27 @@ public void execute() { } private boolean allProjectsMarked() { - return session.getProjects().stream().allMatch(p -> hasState(p) || !hasDeployExecution(p)); + return getProjectsWithDeployExecution().stream().allMatch(this::hasState); + } + + /** + * Returns the list of reactor projects that have a deploy execution, cached on first call. + * The list is invariant during a build and is stored in the first reactor project's plugin + * context to avoid recomputing it on every module invocation (O(N) total instead of O(N²)). + */ + @SuppressWarnings("unchecked") + private List getProjectsWithDeployExecution() { + List allProjects = session.getProjects(); + if (allProjects.isEmpty()) { + return List.of(); + } + Map ctx = session.getPluginContext(allProjects.get(0)); + List cached = (List) ctx.get(PROJECTS_WITH_DEPLOY_KEY); + if (cached == null) { + cached = allProjects.stream().filter(this::hasDeployExecution).collect(Collectors.toList()); + ctx.put(PROJECTS_WITH_DEPLOY_KEY, cached); + } + return cached; } private boolean hasDeployExecution(Project p) {