1 package org.apache.maven.lifecycle.internal.builder.multithreaded;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.List;
23 import java.util.Map;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.CompletionService;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ExecutorCompletionService;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
31
32 import org.apache.maven.execution.MavenSession;
33 import org.apache.maven.lifecycle.internal.BuildThreadFactory;
34 import org.apache.maven.lifecycle.internal.LifecycleModuleBuilder;
35 import org.apache.maven.lifecycle.internal.ProjectBuildList;
36 import org.apache.maven.lifecycle.internal.ProjectSegment;
37 import org.apache.maven.lifecycle.internal.ReactorBuildStatus;
38 import org.apache.maven.lifecycle.internal.ReactorContext;
39 import org.apache.maven.lifecycle.internal.TaskSegment;
40 import org.apache.maven.lifecycle.internal.builder.Builder;
41 import org.apache.maven.project.MavenProject;
42 import org.codehaus.plexus.component.annotations.Component;
43 import org.codehaus.plexus.component.annotations.Requirement;
44 import org.codehaus.plexus.logging.Logger;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 @Component( role = Builder.class, hint = "multithreaded" )
60 public class MultiThreadedBuilder
61 implements Builder
62 {
63
64 @Requirement
65 private Logger logger;
66
67 @Requirement
68 private LifecycleModuleBuilder lifecycleModuleBuilder;
69
70
71 public MultiThreadedBuilder()
72 {
73 }
74
75 @Override
76 public void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
77 List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
78 throws ExecutionException, InterruptedException
79 {
80 int nThreads = Math.min( session.getRequest().getDegreeOfConcurrency(), session.getProjects().size() );
81 boolean parallel = nThreads >= 2;
82
83 session.setParallel( parallel );
84 for ( ProjectSegment segment : projectBuilds )
85 {
86 segment.getSession().setParallel( parallel );
87 }
88 ExecutorService executor = Executors.newFixedThreadPool( nThreads, new BuildThreadFactory() );
89 CompletionService<ProjectSegment> service = new ExecutorCompletionService<>( executor );
90 ConcurrencyDependencyGraph analyzer =
91 new ConcurrencyDependencyGraph( projectBuilds, session.getProjectDependencyGraph() );
92
93
94 ThreadOutputMuxer muxer = null;
95
96 for ( TaskSegment taskSegment : taskSegments )
97 {
98 Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment( taskSegment );
99 try
100 {
101 multiThreadedProjectTaskSegmentBuild( analyzer, reactorContext, session, service, taskSegment,
102 projectBuildMap, muxer );
103 if ( reactorContext.getReactorBuildStatus().isHalted() )
104 {
105 break;
106 }
107 }
108 catch ( Exception e )
109 {
110 session.getResult().addException( e );
111 break;
112 }
113
114 }
115 }
116
117 private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph analyzer,
118 ReactorContext reactorContext, MavenSession rootSession,
119 CompletionService<ProjectSegment> service,
120 TaskSegment taskSegment,
121 Map<MavenProject, ProjectSegment> projectBuildList,
122 ThreadOutputMuxer muxer )
123 {
124
125
126 for ( MavenProject mavenProject : analyzer.getRootSchedulableBuilds() )
127 {
128 ProjectSegment projectSegment = projectBuildList.get( mavenProject );
129 logger.debug( "Scheduling: " + projectSegment.getProject() );
130 Callable<ProjectSegment> cb =
131 createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer );
132 service.submit( cb );
133 }
134
135
136 for ( int i = 0; i < analyzer.getNumberOfBuilds(); i++ )
137 {
138 try
139 {
140 ProjectSegment projectBuild = service.take().get();
141 if ( reactorContext.getReactorBuildStatus().isHalted() )
142 {
143 break;
144 }
145 final List<MavenProject> newItemsThatCanBeBuilt =
146 analyzer.markAsFinished( projectBuild.getProject() );
147 for ( MavenProject mavenProject : newItemsThatCanBeBuilt )
148 {
149 ProjectSegment scheduledDependent = projectBuildList.get( mavenProject );
150 logger.debug( "Scheduling: " + scheduledDependent );
151 Callable<ProjectSegment> cb =
152 createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer );
153 service.submit( cb );
154 }
155 }
156 catch ( InterruptedException e )
157 {
158 rootSession.getResult().addException( e );
159 break;
160 }
161 catch ( ExecutionException e )
162 {
163
164 rootSession.getResult().addException( e );
165 break;
166 }
167 }
168
169
170
171 Future<ProjectSegment> unprocessed;
172 while ( ( unprocessed = service.poll() ) != null )
173 {
174 try
175 {
176 unprocessed.get();
177 }
178 catch ( InterruptedException | ExecutionException e )
179 {
180 throw new RuntimeException( e );
181 }
182 }
183 }
184
185 private Callable<ProjectSegment> createBuildCallable( final MavenSession rootSession,
186 final ProjectSegment projectBuild,
187 final ReactorContext reactorContext,
188 final TaskSegment taskSegment, final ThreadOutputMuxer muxer )
189 {
190 return new Callable<ProjectSegment>()
191 {
192 public ProjectSegment call()
193 {
194
195 lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext,
196 projectBuild.getProject(), taskSegment );
197
198
199 return projectBuild;
200 }
201 };
202 }
203 }