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
60 @Component( role = Builder.class, hint = "multithreaded" )
61 public class MultiThreadedBuilder
62 implements Builder
63 {
64
65 @Requirement
66 private Logger logger;
67
68 @Requirement
69 private LifecycleModuleBuilder lifecycleModuleBuilder;
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
91
92 ThreadOutputMuxer muxer = null;
93
94 for ( TaskSegment taskSegment : taskSegments )
95 {
96 ProjectBuildList segmentProjectBuilds = projectBuilds.getByTaskSegment( taskSegment );
97 Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment( taskSegment );
98 try
99 {
100 ConcurrencyDependencyGraph analyzer =
101 new ConcurrencyDependencyGraph( segmentProjectBuilds,
102 session.getProjectDependencyGraph() );
103 multiThreadedProjectTaskSegmentBuild( analyzer, reactorContext, session, service, taskSegment,
104 projectBuildMap, muxer );
105 if ( reactorContext.getReactorBuildStatus().isHalted() )
106 {
107 break;
108 }
109 }
110 catch ( Exception e )
111 {
112 session.getResult().addException( e );
113 break;
114 }
115
116 }
117 }
118
119 private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph analyzer,
120 ReactorContext reactorContext, MavenSession rootSession,
121 CompletionService<ProjectSegment> service,
122 TaskSegment taskSegment,
123 Map<MavenProject, ProjectSegment> projectBuildList,
124 ThreadOutputMuxer muxer )
125 {
126
127
128 for ( MavenProject mavenProject : analyzer.getRootSchedulableBuilds() )
129 {
130 ProjectSegment projectSegment = projectBuildList.get( mavenProject );
131 logger.debug( "Scheduling: " + projectSegment.getProject() );
132 Callable<ProjectSegment> cb =
133 createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer );
134 service.submit( cb );
135 }
136
137
138 for ( int i = 0; i < analyzer.getNumberOfBuilds(); i++ )
139 {
140 try
141 {
142 ProjectSegment projectBuild = service.take().get();
143 if ( reactorContext.getReactorBuildStatus().isHalted() )
144 {
145 break;
146 }
147
148
149 if ( analyzer.getNumberOfBuilds() > 1 )
150 {
151 final List<MavenProject> newItemsThatCanBeBuilt =
152 analyzer.markAsFinished( projectBuild.getProject() );
153 for ( MavenProject mavenProject : newItemsThatCanBeBuilt )
154 {
155 ProjectSegment scheduledDependent = projectBuildList.get( mavenProject );
156 logger.debug( "Scheduling: " + scheduledDependent );
157 Callable<ProjectSegment> cb =
158 createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer );
159 service.submit( cb );
160 }
161 }
162 }
163 catch ( InterruptedException e )
164 {
165 rootSession.getResult().addException( e );
166 break;
167 }
168 catch ( ExecutionException e )
169 {
170
171 rootSession.getResult().addException( e );
172 break;
173 }
174 }
175
176
177
178 Future<ProjectSegment> unprocessed;
179 while ( ( unprocessed = service.poll() ) != null )
180 {
181 try
182 {
183 unprocessed.get();
184 }
185 catch ( InterruptedException | ExecutionException e )
186 {
187 throw new RuntimeException( e );
188 }
189 }
190 }
191
192 private Callable<ProjectSegment> createBuildCallable( final MavenSession rootSession,
193 final ProjectSegment projectBuild,
194 final ReactorContext reactorContext,
195 final TaskSegment taskSegment, final ThreadOutputMuxer muxer )
196 {
197 return new Callable<ProjectSegment>()
198 {
199 public ProjectSegment call()
200 {
201
202 lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext,
203 projectBuild.getProject(), taskSegment );
204
205
206 return projectBuild;
207 }
208 };
209 }
210 }