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

commit 7da0214d1d77a521ead7971f6c09209a80d1ddf3
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Mon May 16 11:26:49 2022 +0200

    [MNG-7476] Display a warning when an aggregator mojo is locking other mojos 
executions
    
    # Conflicts:
    #       
maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
---
 .../maven/lifecycle/internal/MojoExecutor.java     | 69 +++++++++++++++++++---
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git 
a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
 
b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
index bbd25389e..d251d5195 100644
--- 
a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
+++ 
b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
@@ -29,7 +29,6 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -43,6 +42,7 @@ import 
org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.MultilineMessageHelper;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.lifecycle.MissingProjectException;
 import org.apache.maven.plugin.BuildPluginManager;
@@ -59,6 +59,8 @@ import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.SessionData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * <p>
@@ -76,12 +78,14 @@ import org.eclipse.aether.SessionData;
 public class MojoExecutor
 {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger( 
MojoExecutor.class );
+
     private final BuildPluginManager pluginManager;
     private final MavenPluginManager mavenPluginManager;
     private final LifecycleDependencyResolver lifeCycleDependencyResolver;
     private final ExecutionEventCatapult eventCatapult;
 
-    private final ReadWriteLock aggregatorLock = new ReentrantReadWriteLock();
+    private final OwnerReentrantReadWriteLock aggregatorLock = new 
OwnerReentrantReadWriteLock();
 
     private final Provider<MojosExecutionStrategy> mojosExecutionStrategy;
 
@@ -239,7 +243,7 @@ public class MojoExecutor
     private class ProjectLock implements AutoCloseable
     {
         final Lock acquiredAggregatorLock;
-        final Lock acquiredProjectLock;
+        final OwnerReentrantLock acquiredProjectLock;
 
         ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor )
         {
@@ -249,8 +253,31 @@ public class MojoExecutor
                 boolean aggregator = mojoDescriptor.isAggregator();
                 acquiredAggregatorLock = aggregator ? 
aggregatorLock.writeLock() : aggregatorLock.readLock();
                 acquiredProjectLock = getProjectLock( session );
-                acquiredAggregatorLock.lock();
-                acquiredProjectLock.lock();
+                if ( !acquiredAggregatorLock.tryLock() )
+                {
+                    Thread owner = aggregatorLock.getOwner();
+                    MojoDescriptor ownerMojo = owner != null ? mojos.get( 
owner ) : null;
+                    String str = ownerMojo != null ? " The " + 
ownerMojo.getId() : "An";
+                    String msg = str + " aggregator mojo is already being 
executed "
+                            + "in this parallel build, those kind of mojos 
require exclusive access to "
+                            + "reactor to prevent race conditions. This mojo 
execution will be blocked "
+                            + "until the aggregator mojo is done.";
+                    warn( msg );
+                    acquiredAggregatorLock.lock();
+                }
+                if ( !acquiredProjectLock.tryLock() )
+                {
+                    Thread owner = acquiredProjectLock.getOwner();
+                    MojoDescriptor ownerMojo = owner != null ? mojos.get( 
owner ) : null;
+                    String str = ownerMojo != null ? " The " + 
ownerMojo.getId() : "A";
+                    String msg = str + " mojo is already being executed "
+                            + "on the project " + 
session.getCurrentProject().getGroupId()
+                            + ":" + 
session.getCurrentProject().getArtifactId() + ". "
+                            + "This mojo execution will be blocked "
+                            + "until the mojo is done.";
+                    warn( msg );
+                    acquiredProjectLock.lock();
+                }
             }
             else
             {
@@ -275,13 +302,13 @@ public class MojoExecutor
         }
 
         @SuppressWarnings( { "unchecked", "rawtypes" } )
-        private Lock getProjectLock( MavenSession session )
+        private OwnerReentrantLock getProjectLock( MavenSession session )
         {
             SessionData data = session.getRepositorySession().getData();
             // TODO: when resolver 1.7.3 is released, the code below should be 
changed to
             // TODO: Map<MavenProject, Lock> locks = ( Map ) ((Map) 
data).computeIfAbsent(
             // TODO:         ProjectLock.class, l -> new ConcurrentHashMap<>() 
);
-            Map<MavenProject, Lock> locks = ( Map ) data.get( 
ProjectLock.class );
+            Map<MavenProject, OwnerReentrantLock> locks = ( Map ) data.get( 
ProjectLock.class );
             // initialize the value if not already done (in case of a 
concurrent access) to the method
             if ( locks == null )
             {
@@ -289,7 +316,33 @@ public class MojoExecutor
                 data.set( ProjectLock.class, null, new ConcurrentHashMap<>() );
                 locks = ( Map ) data.get( ProjectLock.class );
             }
-            return locks.computeIfAbsent( session.getCurrentProject(), p -> 
new ReentrantLock() );
+            return locks.computeIfAbsent( session.getCurrentProject(), p -> 
new OwnerReentrantLock() );
+        }
+    }
+
+    static class OwnerReentrantLock extends ReentrantLock
+    {
+        @Override
+        public Thread getOwner()
+        {
+            return super.getOwner();
+        }
+    }
+
+    static class OwnerReentrantReadWriteLock extends ReentrantReadWriteLock
+    {
+        @Override
+        public Thread getOwner()
+        {
+            return super.getOwner();
+        }
+    }
+
+    private static void warn( String msg )
+    {
+        for ( String s : MultilineMessageHelper.format( msg ) )
+        {
+            LOGGER.warn( s );
         }
     }
 

Reply via email to