Skip to content

Commit

Permalink
[MNG-7487] Fix deadlock during forked lifecycle executions
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet authored and michael-o committed May 29, 2022
1 parent 88a03f8 commit eb8bb87
Showing 1 changed file with 33 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public class MojoExecutor

private final ReadWriteLock aggregatorLock = new ReentrantReadWriteLock();

private final Map<Thread, MojoDescriptor> mojos = new ConcurrentHashMap<>();

public MojoExecutor()
{
}
Expand Down Expand Up @@ -206,10 +208,7 @@ private void execute( MavenSession session, MojoExecution mojoExecution, Project
}
}

try ( ProjectLock lock = new ProjectLock( session, mojoDescriptor, aggregatorLock ) )
{
doExecute( session, mojoExecution, projectIndex, dependencyContext );
}
doExecute( session, mojoExecution, projectIndex, dependencyContext );
}

/**
Expand All @@ -220,17 +219,17 @@ private void execute( MavenSession session, MojoExecution mojoExecution, Project
* TODO: ideally, the builder should take care of the ordering in a smarter way
* TODO: and concurrency issues fixed with MNG-7157
*/
private static class ProjectLock implements AutoCloseable
private class ProjectLock implements AutoCloseable
{
final Lock acquiredAggregatorLock;
final Lock acquiredProjectLock;

ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor, ReadWriteLock aggregatorLock )
ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor )
{
if ( session.getRequest().getDegreeOfConcurrency() > 1 )
{
boolean aggregator = mojoDescriptor.isAggregator();
acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock();
acquiredAggregatorLock = mojoDescriptor.isAggregator()
? aggregatorLock.writeLock() : aggregatorLock.readLock();
acquiredProjectLock = getProjectLock( session );
acquiredAggregatorLock.lock();
acquiredProjectLock.lock();
Expand Down Expand Up @@ -260,13 +259,13 @@ public void close()
private Lock getProjectLock( MavenSession session )
{
SessionData data = session.getRepositorySession().getData();
ConcurrentMap<MavenProject, Lock> locks = ( ConcurrentMap ) data.get( ProjectLock.class );
ConcurrentMap<MavenProject, Lock> locks = (ConcurrentMap) data.get( ProjectLock.class );
// initialize the value if not already done (in case of a concurrent access) to the method
if ( locks == null )
{
// the call to data.set(k, null, v) is effectively a call to data.putIfAbsent(k, v)
data.set( ProjectLock.class, null, new ConcurrentHashMap<>() );
locks = ( ConcurrentMap ) data.get( ProjectLock.class );
locks = (ConcurrentMap) data.get( ProjectLock.class );
}
Lock acquiredProjectLock = locks.get( session.getCurrentProject() );
if ( acquiredProjectLock == null )
Expand All @@ -292,8 +291,31 @@ private void doExecute( MavenSession session, MojoExecution mojoExecution, Proje

ensureDependenciesAreResolved( mojoDescriptor, session, dependencyContext );

eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution );
try
{
mojos.put( Thread.currentThread(), mojoDescriptor );
try ( ProjectLock lock = new ProjectLock( session, mojoDescriptor ) )
{
doExecute2( session, mojoExecution );
}
finally
{
mojos.remove( Thread.currentThread() );
}
}
finally
{
for ( MavenProject forkedProject : forkedProjects )
{
forkedProject.setExecutionProject( null );
}
}
}

private void doExecute2( MavenSession session, MojoExecution mojoExecution )
throws LifecycleExecutionException
{
eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution );
try
{
try
Expand All @@ -314,13 +336,6 @@ private void doExecute( MavenSession session, MojoExecution mojoExecution, Proje

throw e;
}
finally
{
for ( MavenProject forkedProject : forkedProjects )
{
forkedProject.setExecutionProject( null );
}
}
}

public void ensureDependenciesAreResolved( MojoDescriptor mojoDescriptor, MavenSession session,
Expand Down

0 comments on commit eb8bb87

Please sign in to comment.