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 2022/11/09 13:13:27 UTC

[maven] branch master updated: [MNG-7583] Allow concurrent access to the MavenPluginManager (#855)

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

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new dfcf5791f [MNG-7583] Allow concurrent access to the MavenPluginManager (#855)
dfcf5791f is described below

commit dfcf5791fcc92ab82fc0cdb9f14aa372140c7a08
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Nov 9 14:13:18 2022 +0100

    [MNG-7583] Allow concurrent access to the MavenPluginManager (#855)
---
 .../maven/plugin/DefaultPluginDescriptorCache.java | 41 ++++++++++++++++++-
 .../maven/plugin/DefaultPluginRealmCache.java      | 32 +++++++++++++++
 .../apache/maven/plugin/PluginDescriptorCache.java | 10 +++++
 .../org/apache/maven/plugin/PluginRealmCache.java  |  9 +++++
 .../plugin/internal/DefaultMavenPluginManager.java | 46 ++++++++++------------
 5 files changed, 110 insertions(+), 28 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
index 557026362..9e78b3c9b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
@@ -20,10 +20,10 @@ package org.apache.maven.plugin;
  */
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -55,7 +55,7 @@ public class DefaultPluginDescriptorCache
     implements PluginDescriptorCache
 {
 
-    private Map<Key, PluginDescriptor> descriptors = new HashMap<>( 128 );
+    private Map<Key, PluginDescriptor> descriptors = new ConcurrentHashMap<>( 128 );
 
     public void flush()
     {
@@ -72,6 +72,43 @@ public class DefaultPluginDescriptorCache
         return clone( descriptors.get( cacheKey ) );
     }
 
+    @Override
+    public PluginDescriptor get( Key key, PluginDescriptorSupplier supplier )
+            throws PluginDescriptorParsingException, PluginResolutionException, InvalidPluginDescriptorException
+    {
+        try
+        {
+            return clone( descriptors.computeIfAbsent( key, k ->
+            {
+                try
+                {
+                    return clone( supplier.load() );
+                }
+                catch ( PluginDescriptorParsingException | PluginResolutionException
+                        | InvalidPluginDescriptorException e )
+                {
+                    throw new RuntimeException( e );
+                }
+            } ) );
+        }
+        catch ( RuntimeException e )
+        {
+            if ( e.getCause() instanceof PluginDescriptorParsingException )
+            {
+                throw (PluginDescriptorParsingException) e.getCause();
+            }
+            if ( e.getCause() instanceof PluginResolutionException )
+            {
+                throw (PluginResolutionException) e.getCause();
+            }
+            if ( e.getCause() instanceof InvalidPluginDescriptorException )
+            {
+                throw (InvalidPluginDescriptorException) e.getCause();
+            }
+            throw e;
+        }
+    }
+
     public void put( Key cacheKey, PluginDescriptor pluginDescriptor )
     {
         descriptors.put( cacheKey, clone( pluginDescriptor ) );
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
index fef5fe1d1..687cb9357 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
@@ -159,6 +159,38 @@ public class DefaultPluginRealmCache
         return cache.get( key );
     }
 
+    @Override
+    public CacheRecord get( Key key, PluginRealmSupplier supplier )
+            throws PluginResolutionException, PluginContainerException
+    {
+        try
+        {
+            return cache.computeIfAbsent( key, k ->
+            {
+                try
+                {
+                    return supplier.load();
+                }
+                catch ( PluginResolutionException | PluginContainerException e )
+                {
+                    throw new RuntimeException( e );
+                }
+            } );
+        }
+        catch ( RuntimeException e )
+        {
+            if ( e.getCause() instanceof PluginResolutionException )
+            {
+                throw (PluginResolutionException) e.getCause();
+            }
+            if ( e.getCause() instanceof PluginContainerException )
+            {
+                throw (PluginContainerException) e.getCause();
+            }
+            throw e;
+        }
+    }
+
     public CacheRecord put( Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts )
     {
         Objects.requireNonNull( pluginRealm, "pluginRealm cannot be null" );
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
index 08b4f1bc3..646b506d2 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
@@ -47,12 +47,22 @@ public interface PluginDescriptorCache
         // marker interface for cache keys
     }
 
+    @FunctionalInterface
+    interface PluginDescriptorSupplier
+    {
+        PluginDescriptor load()
+                throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
+    }
+
     Key createKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session );
 
     void put( Key key, PluginDescriptor pluginDescriptor );
 
     PluginDescriptor get( Key key );
 
+    PluginDescriptor get( Key key, PluginDescriptorSupplier supplier )
+            throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
+
     void flush();
 
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
index 78c3ae6f3..fecfaccfb 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
@@ -74,12 +74,21 @@ public interface PluginRealmCache
         // marker interface for cache keys
     }
 
+    @FunctionalInterface
+    interface PluginRealmSupplier
+    {
+        CacheRecord load() throws PluginResolutionException, PluginContainerException;
+    }
+
     Key createKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
                    DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
                    RepositorySystemSession session );
 
     CacheRecord get( Key key );
 
+    CacheRecord get( Key key, PluginRealmSupplier supplier )
+            throws PluginResolutionException, PluginContainerException;
+
     CacheRecord put( Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts );
 
     void flush();
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
index 5496eef14..8fdfb3e9a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
@@ -184,31 +184,29 @@ public class DefaultMavenPluginManager
         this.prerequisitesCheckers = prerequisitesCheckers;
     }
 
-    public synchronized PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories,
-                                                             RepositorySystemSession session )
+    public PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories,
+                                                 RepositorySystemSession session )
         throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
     {
         PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey( plugin, repositories, session );
 
-        PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey );
-
-        if ( pluginDescriptor == null )
+        PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey, () ->
         {
             org.eclipse.aether.artifact.Artifact artifact =
                 pluginDependenciesResolver.resolve( plugin, repositories, session );
 
             Artifact pluginArtifact = RepositoryUtils.toArtifact( artifact );
 
-            pluginDescriptor = extractPluginDescriptor( pluginArtifact, plugin );
+            PluginDescriptor descriptor = extractPluginDescriptor( pluginArtifact, plugin );
 
-            if ( StringUtils.isBlank( pluginDescriptor.getRequiredMavenVersion() ) )
+            if ( StringUtils.isBlank( descriptor.getRequiredMavenVersion() ) )
             {
                 // only take value from underlying POM if plugin descriptor has no explicit Maven requirement
-                pluginDescriptor.setRequiredMavenVersion( artifact.getProperty( "requiredMavenVersion", null ) );
+                descriptor.setRequiredMavenVersion( artifact.getProperty( "requiredMavenVersion", null ) );
             }
 
-            pluginDescriptorCache.put( cacheKey, pluginDescriptor );
-        }
+            return descriptor;
+        } );
 
         pluginDescriptor.setPlugin( plugin );
 
@@ -345,8 +343,8 @@ public class DefaultMavenPluginManager
         }
     }
 
-    public synchronized void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session,
-                                               ClassLoader parent, List<String> imports, DependencyFilter filter )
+    public void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session,
+                                  ClassLoader parent, List<String> imports, DependencyFilter filter )
         throws PluginResolutionException, PluginContainerException
     {
         Plugin plugin = pluginDescriptor.getPlugin();
@@ -386,23 +384,19 @@ public class DefaultMavenPluginManager
                                                                         project.getRemotePluginRepositories(),
                                                                         session.getRepositorySession() );
 
-            PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get( cacheKey );
-
-            if ( cacheRecord != null )
-            {
-                pluginDescriptor.setClassRealm( cacheRecord.getRealm() );
-                pluginDescriptor.setArtifacts( new ArrayList<>( cacheRecord.getArtifacts() ) );
-                for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
-                {
-                    componentDescriptor.setRealm( cacheRecord.getRealm() );
-                }
-            }
-            else
+            PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get( cacheKey, () ->
             {
                 createPluginRealm( pluginDescriptor, session, parent, foreignImports, filter );
 
-                cacheRecord =
-                    pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() );
+                return new PluginRealmCache.CacheRecord(
+                        pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() );
+            } );
+
+            pluginDescriptor.setClassRealm( cacheRecord.getRealm() );
+            pluginDescriptor.setArtifacts( new ArrayList<>( cacheRecord.getArtifacts() ) );
+            for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
+            {
+                componentDescriptor.setRealm( cacheRecord.getRealm() );
             }
 
             pluginRealmCache.register( project, cacheKey, cacheRecord );