You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/08/03 00:36:48 UTC

(maven-install-plugin) 01/01: Cache projectsUsingPlugin list to avoid O(N²) reactor scan

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch quick-fix/cache-projects-using-plugin
in repository https://gitbox.apache.org/repos/asf/maven-install-plugin.git

commit 05e6221587f26c87282769820e9d9088e2ff1301
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Mon Aug 3 02:36:22 2026 +0200

    Cache projectsUsingPlugin list to avoid O(N²) reactor scan
    
    InstallMojo.execute() computes the list of reactor projects using
    the install plugin on every module invocation by streaming over all
    projects and calling getPluginsAsMap() for each one. In a 4383-module
    reactor, this produces ~19.2M filter evaluations (4383² calls).
    
    JFR profiling shows this as 5.6% of total CPU time, all in
    PluginContainer.getPluginsAsMap() called from usingPlugin().
    
    Fix: cache the computed list in the first reactor project's plugin
    context on first invocation. The list is invariant during a build —
    which projects have the install plugin configured does not change
    between module invocations. This turns O(N²) into O(N).
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 .../apache/maven/plugins/install/InstallMojo.java  | 24 ++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java
index d002520..f3183f5 100644
--- a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java
+++ b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java
@@ -98,6 +98,7 @@ public class InstallMojo implements org.apache.maven.api.plugin.Mojo {
     }
 
     private static final String INSTALL_PROCESSED_MARKER = InstallMojo.class.getName() + ".processed";
+    private static final String PROJECTS_USING_PLUGIN_KEY = InstallMojo.class.getName() + ".projectsUsingPlugin";
 
     public InstallMojo() {}
 
@@ -120,6 +121,26 @@ public class InstallMojo implements org.apache.maven.api.plugin.Mojo {
         return pluginContext.containsKey(INSTALL_PROCESSED_MARKER);
     }
 
+    /**
+     * Returns the list of reactor projects that have this plugin configured, cached on first call.
+     * The list is invariant during a build and is stored in the current project's plugin
+     * context to avoid recomputing it on every module invocation (O(N) total instead of O(N²)).
+     */
+    @SuppressWarnings("unchecked")
+    private List<Project> getProjectsUsingPlugin() {
+        List<Project> allProjects = session.getProjects();
+        if (allProjects.isEmpty()) {
+            return List.of();
+        }
+        Map<String, Object> ctx = session.getPluginContext(allProjects.get(0));
+        List<Project> cached = (List<Project>) ctx.get(PROJECTS_USING_PLUGIN_KEY);
+        if (cached == null) {
+            cached = allProjects.stream().filter(this::usingPlugin).collect(Collectors.toList());
+            ctx.put(PROJECTS_USING_PLUGIN_KEY, cached);
+        }
+        return cached;
+    }
+
     private boolean usingPlugin(Project project) {
         Plugin plugin = project.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:maven-install-plugin");
         return plugin != null
@@ -144,8 +165,7 @@ public class InstallMojo implements org.apache.maven.api.plugin.Mojo {
             }
         }
 
-        List<Project> projectsUsingPlugin =
-                session.getProjects().stream().filter(this::usingPlugin).collect(Collectors.toList());
+        List<Project> projectsUsingPlugin = getProjectsUsingPlugin();
         if (allProjectsMarked(projectsUsingPlugin)) {
             for (Project reactorProject : projectsUsingPlugin) {
                 State state = getState(reactorProject);