mirror of https://github.com/apache/maven.git
[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
This commit is contained in:
parent
2a276d0dcf
commit
7da0214d1d
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue