View | Details | Raw Unified | Return to bug 126121 | Differences between
and this patch

Collapse All | Expand All

(-)a/.gitignore (-1 / +2 lines)
Lines 8-11 javacore.* Link Here
8
heapdump.*
8
heapdump.*
9
core.*
9
core.*
10
Snap.*
10
Snap.*
11
11
target
12
tests/*/*.jar
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildDescription.java (+42 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial API
10
 *     Morgan Stanley - [126121] Updated parallel build patch by fixing concurrency issues 
11
 *******************************************************************************/
12
package org.eclipse.core.internal.events;
13
14
import org.eclipse.core.resources.IBuildConfiguration;
15
import org.eclipse.core.resources.IBuildContext;
16
17
import org.eclipse.core.resources.IBuildDescription;
18
19
/**
20
 * 
21
 */
22
public class BuildDescription implements IBuildDescription {
23
24
	private IBuildContext buildContext;
25
	
26
	private IBuildConfiguration buildConfiguration;
27
	
28
	public BuildDescription(IBuildContext buildContext, IBuildConfiguration buildConfiguration) {
29
		super();
30
		this.buildContext = buildContext;
31
		this.buildConfiguration = buildConfiguration;
32
	}
33
	
34
	public IBuildContext getBuildContext() {
35
		return buildContext;
36
	}
37
38
	public IBuildConfiguration getBuildConfiguration() {
39
		return buildConfiguration;
40
	}
41
42
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java (-92 / +245 lines)
Lines 11-16 Link Here
11
 * Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule
11
 * Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule
12
 * James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule()
12
 * James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule()
13
 * Broadcom Corporation - ongoing development
13
 * Broadcom Corporation - ongoing development
14
 * 	   Jens Kuebler - [126121] - Initial changes to support parallel build
15
 * 	   Morgan Stanley - [126121] Fixing parallel build concurrency issues
14
 *******************************************************************************/
16
 *******************************************************************************/
15
package org.eclipse.core.internal.events;
17
package org.eclipse.core.internal.events;
16
18
Lines 99-108 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
99
	private final Set<IProject> builtProjects = new HashSet<IProject>();
101
	private final Set<IProject> builtProjects = new HashSet<IProject>();
100
102
101
	//the following four fields only apply for the lifetime of a single builder invocation.
103
	//the following four fields only apply for the lifetime of a single builder invocation.
102
	protected InternalBuilder currentBuilder;
104
	protected final ThreadLocal<InternalBuilder> currentBuilder = new ThreadLocal<InternalBuilder>();
103
	private DeltaDataTree currentDelta;
105
	private final ThreadLocal<DeltaDataTree> currentDelta = new ThreadLocal<DeltaDataTree>();
104
	private ElementTree currentLastBuiltTree;
106
	private final ThreadLocal<ElementTree> currentLastBuiltTree = new ThreadLocal<ElementTree>();
105
	private ElementTree currentTree;
107
	private final ThreadLocal<ElementTree> currentTree = new ThreadLocal<ElementTree>();
106
108
107
	/**
109
	/**
108
	 * Caches the IResourceDelta for a pair of trees
110
	 * Caches the IResourceDelta for a pair of trees
Lines 134-151 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
134
136
135
	private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map<String, String> args, MultiStatus status, IProgressMonitor monitor) {
137
	private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map<String, String> args, MultiStatus status, IProgressMonitor monitor) {
136
		try {
138
		try {
137
			currentBuilder = builder;
139
		    // flag required for different locking behaviour
140
		    boolean notParallel = !(trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD || trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD);
141
		    
142
		    // Builder impl may not know about Parallel build types and it is not even interesting on the per project level
143
		    if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) {
144
		        trigger = IncrementalProjectBuilder.FULL_BUILD;
145
		    }
146
		    if (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) {
147
		        trigger = IncrementalProjectBuilder.CLEAN_BUILD;
148
		    }
149
 
150
		    currentBuilder.set(builder);
138
			//clear any old requests to forget built state
151
			//clear any old requests to forget built state
139
			currentBuilder.clearLastBuiltStateRequests();
152
			currentBuilder.get().clearLastBuiltStateRequests();
140
			// Figure out want kind of build is needed
153
			// Figure out want kind of build is needed
141
			boolean clean = trigger == IncrementalProjectBuilder.CLEAN_BUILD;
154
			boolean clean = (trigger == IncrementalProjectBuilder.CLEAN_BUILD);
142
			currentLastBuiltTree = currentBuilder.getLastBuiltTree();
155
			currentLastBuiltTree.set(currentBuilder.get().getLastBuiltTree());
143
156
144
			// Does the build command respond to this trigger?
157
			// Does the build command respond to this trigger?
145
			boolean isBuilding = builder.getCommand().isBuilding(trigger);
158
			boolean isBuilding = builder.getCommand().isBuilding(trigger);
146
159
147
			// If no tree is available we have to do a full build
160
			// If no tree is available we have to do a full build
148
			if (!clean && currentLastBuiltTree == null) {
161
			if (!clean && currentLastBuiltTree.get() == null) {
149
				// Bug 306746 - Don't promote build to FULL_BUILD if builder doesn't AUTO_BUILD
162
				// Bug 306746 - Don't promote build to FULL_BUILD if builder doesn't AUTO_BUILD
150
				if (trigger == IncrementalProjectBuilder.AUTO_BUILD && !isBuilding)
163
				if (trigger == IncrementalProjectBuilder.AUTO_BUILD && !isBuilding)
151
					return;
164
					return;
Lines 157-180 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
157
			//don't build if this builder doesn't respond to the trigger
170
			//don't build if this builder doesn't respond to the trigger
158
			if (!isBuilding) {
171
			if (!isBuilding) {
159
				if (clean)
172
				if (clean)
160
					currentBuilder.setLastBuiltTree(null);
173
					currentBuilder.get().setLastBuiltTree(null);
161
				return;
174
				return;
162
			}
175
			}
163
176
164
			// For incremental builds, grab a pointer to the current state before computing the delta
177
			// For incremental builds, grab a pointer to the current state before computing the delta
165
			currentTree = ((trigger == IncrementalProjectBuilder.FULL_BUILD) || clean) ? null : workspace.getElementTree();
178
			currentTree.set(((trigger == IncrementalProjectBuilder.FULL_BUILD) || clean) ? null : workspace.getElementTree());
166
			int depth = -1;
179
			int depth = -1;
167
			ISchedulingRule rule = null;
180
			ISchedulingRule rule = null;
168
			try {
181
			try {
169
				//short-circuit if none of the projects this builder cares about have changed.
182
				//short-circuit if none of the projects this builder cares about have changed.
170
				if (!needsBuild(currentBuilder, trigger)) {
183
				if (!needsBuild(currentBuilder.get(), trigger)) {
171
					//use up the progress allocated for this builder
184
					//use up the progress allocated for this builder
172
					monitor.beginTask("", 1); //$NON-NLS-1$
185
					monitor.beginTask("", 1); //$NON-NLS-1$
173
					monitor.done();
186
					monitor.done();
174
					return;
187
					return;
175
				}
188
				}
176
				rule = builder.getRule(trigger, args);
189
				rule = builder.getRule(trigger, args);
177
				String name = currentBuilder.getLabel();
190
				String name = currentBuilder.get().getLabel();
178
				String message;
191
				String message;
179
				if (name != null)
192
				if (name != null)
180
					message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath());
193
					message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath());
Lines 183-230 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
183
				monitor.subTask(message);
196
				monitor.subTask(message);
184
				hookStartBuild(builder, trigger);
197
				hookStartBuild(builder, trigger);
185
				// Make the current tree immutable before releasing the WS lock
198
				// Make the current tree immutable before releasing the WS lock
186
				if (rule != null && currentTree != null)
199
				if (rule != null && currentTree.get() != null)
187
					workspace.newWorkingTree();
200
					workspace.newWorkingTree();
188
				//release workspace lock while calling builders
201
				//release workspace lock while calling builders
189
				depth = getWorkManager().beginUnprotected();
202
				if (notParallel) {
203
				    depth = getWorkManager().beginUnprotected();
204
				}
190
				// Acquire the rule required for running this builder
205
				// Acquire the rule required for running this builder
191
				if (rule != null) {
206
				if (rule != null) {
192
					Job.getJobManager().beginRule(rule, monitor);
207
					Job.getJobManager().beginRule(rule, monitor);
193
					// Now that we've acquired the rule, changes may have been made concurrently, ensure we're pointing at the 
208
					// Now that we've acquired the rule, changes may have been made concurrently, ensure we're pointing at the 
194
					// correct currentTree so delta contains concurrent changes made in areas guarded by the scheduling rule
209
					// correct currentTree so delta contains concurrent changes made in areas guarded by the scheduling rule
195
					if (currentTree != null)
210
					if (currentTree.get() != null)
196
						currentTree = workspace.getElementTree();
211
						currentTree.set(workspace.getElementTree());
197
				}
212
				}
198
				//do the build
213
				//do the build
199
				SafeRunner.run(getSafeRunnable(trigger, args, status, monitor));
214
				SafeRunner.run(getSafeRunnable(trigger, args, status, monitor, currentBuilder.get()));
200
			} finally {
215
			} finally {
201
				// Re-acquire the WS lock, then release the scheduling rule
216
				// Re-acquire the WS lock, then release the scheduling rule
202
				if (depth >= 0)
217
			    if (notParallel && depth >= 0)
203
					getWorkManager().endUnprotected(depth);
218
					getWorkManager().endUnprotected(depth);
204
				if (rule != null)
219
				if (rule != null)
205
					Job.getJobManager().endRule(rule);
220
					Job.getJobManager().endRule(rule);
206
				// Be sure to clean up after ourselves.
221
				// Be sure to clean up after ourselves.
207
				if (clean || currentBuilder.wasForgetStateRequested()) {
222
				if (clean || currentBuilder.get().wasForgetStateRequested()) {
208
					currentBuilder.setLastBuiltTree(null);
223
					currentBuilder.get().setLastBuiltTree(null);
209
				} else if (currentBuilder.wasRememberStateRequested()) {
224
				} else if (currentBuilder.get().wasRememberStateRequested()) {
210
					// If remember last build state, and FULL_BUILD
225
					// If remember last build state, and FULL_BUILD
211
					// last tree must be set to => null for next build
226
					// last tree must be set to => null for next build
212
					if (trigger == IncrementalProjectBuilder.FULL_BUILD)
227
					if (trigger == IncrementalProjectBuilder.FULL_BUILD)
213
						currentBuilder.setLastBuiltTree(null);
228
						currentBuilder.get().setLastBuiltTree(null);
214
					// else don't modify the last built tree
229
					// else don't modify the last built tree
215
				} else {
230
				} else {
216
					// remember the current state as the last built state.
231
					// remember the current state as the last built state.
217
					ElementTree lastTree = workspace.getElementTree();
232
					ElementTree lastTree = workspace.getElementTree();
218
					lastTree.immutable();
233
//					lastTree.immutable();
219
					currentBuilder.setLastBuiltTree(lastTree);
234
					currentBuilder.get().setLastBuiltTree(lastTree);
220
				}
235
				}
221
				hookEndBuild(builder);
236
				hookEndBuild(builder);
222
			}
237
			}
223
		} finally {
238
		} finally {
224
			currentBuilder = null;
239
		    currentBuilder.set(null);
225
			currentTree = null;
240
		    currentTree.set(null);
226
			currentLastBuiltTree = null;
241
		    currentLastBuiltTree.set(null);
227
			currentDelta = null;
242
		    currentDelta.set(null);
228
		}
243
		}
229
	}
244
	}
230
245
Lines 234-240 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
234
				checkCanceled(trigger, monitor);
249
				checkCanceled(trigger, monitor);
235
				BuildCommand command = (BuildCommand) commands[i];
250
				BuildCommand command = (BuildCommand) commands[i];
236
				IProgressMonitor sub = Policy.subMonitorFor(monitor, 1);
251
				IProgressMonitor sub = Policy.subMonitorFor(monitor, 1);
237
				IncrementalProjectBuilder builder = getBuilder(buildConfiguration, command, i, status, context);
252
				IncrementalProjectBuilder builder;
253
				if(IncrementalProjectBuilder.PARALLEL_FULL_BUILD == trigger || IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD == trigger) {
254
				    builder = getParallelBuilder(buildConfiguration, command, i, status, context);
255
				} else {
256
				    builder = getBuilder(buildConfiguration, command, i, status, context);
257
				}
238
				if (builder != null)
258
				if (builder != null)
239
					basicBuild(trigger, builder, command.getArguments(false), status, sub);
259
					basicBuild(trigger, builder, command.getArguments(false), status, sub);
240
			}
260
			}
Lines 362-387 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
362
	 * they are given.
382
	 * they are given.
363
	 * @return A status indicating if the build succeeded or failed
383
	 * @return A status indicating if the build succeeded or failed
364
	 */
384
	 */
365
	public IStatus build(IBuildConfiguration[] configs, IBuildConfiguration[] requestedConfigs, int trigger, IProgressMonitor monitor) {
385
    public IStatus build(final IBuildConfiguration[] configs, final IBuildConfiguration[] requestedConfigs, final int trigger, final IProgressMonitor monitor) {
366
		monitor = Policy.monitorFor(monitor);
386
        if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD || trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) {
367
		try {
387
            
368
			monitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK);
388
            final String buildType = (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) ? "Parallel full build" : "Parallel clean build";
369
			if (!canRun(trigger))
389
            Job job = new Job(buildType) {
370
				return Status.OK_STATUS;
390
                
371
			try {
391
                @Override
372
				hookStartBuild(configs, trigger);
392
                protected IStatus run(IProgressMonitor monitor) {
373
				MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null);
393
                    try {
374
				basicBuildLoop(configs, requestedConfigs, trigger, status, monitor);
394
                        IBuildConfiguration[] buildConfigs = requestedConfigs.length > 0 ? requestedConfigs : configs; 
375
				return status;
395
                        if (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD) {                            
376
			} finally {
396
                            buildParallel(IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD, monitor, buildConfigs);
377
				hookEndBuild(trigger);
397
                        }
378
			}
398
                        buildParallel(IncrementalProjectBuilder.PARALLEL_FULL_BUILD, monitor, buildConfigs);
379
		} finally {
399
                    } catch (CoreException e) {
380
			monitor.done();
400
                        e.printStackTrace();
381
			if (trigger == IncrementalProjectBuilder.INCREMENTAL_BUILD || trigger == IncrementalProjectBuilder.FULL_BUILD)
401
                        return new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, buildType + " finished with error", e);
382
				autoBuildJob.avoidBuild();
402
                    } 
383
		}
403
                    
384
	}
404
                    return new Status(IStatus.OK, ResourcesPlugin.PI_RESOURCES, buildType + " finished successfully");
405
                }
406
            };
407
            
408
            job.setPriority(Job.LONG);
409
            job.schedule();
410
411
            autoBuildJob.avoidBuild();
412
            
413
            return Status.OK_STATUS;
414
            
415
        } else {            
416
            IProgressMonitor myMonitor = Policy.monitorFor(monitor);
417
            try {
418
                myMonitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK);
419
                if (!canRun(trigger))
420
                    return Status.OK_STATUS;
421
                try {
422
                    hookStartBuild(configs, trigger);
423
                    MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null);
424
                    basicBuildLoop(configs, requestedConfigs, trigger, status, myMonitor);
425
                    return status;
426
                } finally {
427
                    hookEndBuild(trigger);
428
                }
429
            } finally {
430
                myMonitor.done();
431
                if (trigger == IncrementalProjectBuilder.INCREMENTAL_BUILD || trigger == IncrementalProjectBuilder.FULL_BUILD)
432
                    autoBuildJob.avoidBuild();
433
            }
434
        }
435
    }
385
436
386
	/**
437
	/**
387
	 * Runs the builder with the given name on the given project config.
438
	 * Runs the builder with the given name on the given project config.
Lines 480-492 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
480
	}
531
	}
481
532
482
	private String debugBuilder() {
533
	private String debugBuilder() {
483
		return currentBuilder == null ? "<no builder>" : currentBuilder.getClass().getName(); //$NON-NLS-1$
534
		return currentBuilder.get() == null ? "<no builder>" : currentBuilder.get().getClass().getName(); //$NON-NLS-1$
484
	}
535
	}
485
536
486
	private String debugProject() {
537
	private String debugProject() {
487
		if (currentBuilder == null)
538
		if (currentBuilder.get() == null)
488
			return "<no project>"; //$NON-NLS-1$
539
			return "<no project>"; //$NON-NLS-1$
489
		return currentBuilder.getProject().getFullPath().toString();
540
		return currentBuilder.get().getProject().getFullPath().toString();
490
	}
541
	}
491
542
492
	/**
543
	/**
Lines 498-505 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
498
		switch (trigger) {
549
		switch (trigger) {
499
			case IncrementalProjectBuilder.FULL_BUILD :
550
			case IncrementalProjectBuilder.FULL_BUILD :
500
				return "FULL_BUILD"; //$NON-NLS-1$
551
				return "FULL_BUILD"; //$NON-NLS-1$
552
			case IncrementalProjectBuilder.PARALLEL_FULL_BUILD :
553
			    return "PARALLEL_FULL_BUILD"; //$NON-NLS-1$
501
			case IncrementalProjectBuilder.CLEAN_BUILD :
554
			case IncrementalProjectBuilder.CLEAN_BUILD :
502
				return "CLEAN_BUILD"; //$NON-NLS-1$
555
				return "CLEAN_BUILD"; //$NON-NLS-1$
556
			case IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD :
557
			    return "PARALLEL_CLEAN_BUILD"; //$NON-NLS-1$
503
			case IncrementalProjectBuilder.AUTO_BUILD :
558
			case IncrementalProjectBuilder.AUTO_BUILD :
504
			case IncrementalProjectBuilder.INCREMENTAL_BUILD :
559
			case IncrementalProjectBuilder.INCREMENTAL_BUILD :
505
			default :
560
			default :
Lines 581-598 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
581
		//try to match on builder index, but if not match is found, use the builder name and config name
636
		//try to match on builder index, but if not match is found, use the builder name and config name
582
		//this is because older workspace versions did not store builder infos in build spec order
637
		//this is because older workspace versions did not store builder infos in build spec order
583
		BuilderPersistentInfo nameMatch = null;
638
		BuilderPersistentInfo nameMatch = null;
584
		for (Iterator<BuilderPersistentInfo> it = infos.iterator(); it.hasNext();) {
639
		synchronized(infos) {
585
			BuilderPersistentInfo info = it.next();
640
    		for (Iterator<BuilderPersistentInfo> it = infos.iterator(); it.hasNext();) {
586
			// match on name, config name and build spec index if known
641
    			BuilderPersistentInfo info = it.next();
587
			// Note: the config name may be null for builders that don't support configurations, or old workspaces
642
    			// match on name, config name and build spec index if known
588
			if (info.getBuilderName().equals(builderName) && (info.getConfigName() == null || info.getConfigName().equals(configName))) {
643
    			// Note: the config name may be null for builders that don't support configurations, or old workspaces
589
				//we have found a match on name alone
644
    			if (info.getBuilderName().equals(builderName) && (info.getConfigName() == null || info.getConfigName().equals(configName))) {
590
				if (nameMatch == null)
645
    				//we have found a match on name alone
591
					nameMatch = info;
646
    				if (nameMatch == null)
592
				//see if the index matches
647
    					nameMatch = info;
593
				if (buildSpecIndex == -1 || info.getBuildSpecIndex() == -1 || buildSpecIndex == info.getBuildSpecIndex())
648
    				//see if the index matches
594
					return info;
649
    				if (buildSpecIndex == -1 || info.getBuildSpecIndex() == -1 || buildSpecIndex == info.getBuildSpecIndex())
595
			}
650
    					return info;
651
    			}
652
    		}
596
		}
653
		}
597
		//no exact index match, so return name match, if any
654
		//no exact index match, so return name match, if any
598
		return nameMatch;
655
		return nameMatch;
Lines 645-651 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
645
	IResourceDelta getDelta(IProject project) {
702
	IResourceDelta getDelta(IProject project) {
646
		try {
703
		try {
647
			lock.acquire();
704
			lock.acquire();
648
			if (currentTree == null) {
705
			if (currentTree.get() == null) {
649
				if (Policy.DEBUG_BUILD_FAILURE)
706
				if (Policy.DEBUG_BUILD_FAILURE)
650
					Policy.debug("Build: no tree for delta " + debugBuilder() + " [" + debugProject() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
707
					Policy.debug("Build: no tree for delta " + debugBuilder() + " [" + debugProject() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
651
				return null;
708
				return null;
Lines 657-663 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
657
				return null;
714
				return null;
658
			}
715
			}
659
			//check if this project has changed
716
			//check if this project has changed
660
			if (currentDelta != null && currentDelta.findNodeAt(project.getFullPath()) == null) {
717
			if (currentDelta.get() != null && currentDelta.get().findNodeAt(project.getFullPath()) == null) {
661
				//if the project never existed (not in delta and not in current tree), return null
718
				//if the project never existed (not in delta and not in current tree), return null
662
				if (!project.exists())
719
				if (!project.exists())
663
					return null;
720
					return null;
Lines 665-671 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
665
				return ResourceDeltaFactory.newEmptyDelta(project);
722
				return ResourceDeltaFactory.newEmptyDelta(project);
666
			}
723
			}
667
			//now check against the cache
724
			//now check against the cache
668
			IResourceDelta result = (IResourceDelta) deltaCache.getDelta(project.getFullPath(), currentLastBuiltTree, currentTree);
725
			IResourceDelta result = (IResourceDelta) deltaCache.getDelta(project.getFullPath(), currentLastBuiltTree.get(), currentTree.get());
669
			if (result != null)
726
			if (result != null)
670
				return result;
727
				return result;
671
728
Lines 674-681 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
674
				startTime = System.currentTimeMillis();
731
				startTime = System.currentTimeMillis();
675
				Policy.debug("Computing delta for project: " + project.getName()); //$NON-NLS-1$
732
				Policy.debug("Computing delta for project: " + project.getName()); //$NON-NLS-1$
676
			}
733
			}
677
			result = ResourceDeltaFactory.computeDelta(workspace, currentLastBuiltTree, currentTree, project.getFullPath(), -1);
734
			result = ResourceDeltaFactory.computeDelta(workspace, currentLastBuiltTree.get(), currentTree.get(), project.getFullPath(), -1);
678
			deltaCache.cache(project.getFullPath(), currentLastBuiltTree, currentTree, result);
735
			deltaCache.cache(project.getFullPath(), currentLastBuiltTree.get(), currentTree.get(), result);
679
			if (Policy.DEBUG_BUILD_FAILURE && result == null)
736
			if (Policy.DEBUG_BUILD_FAILURE && result == null)
680
				Policy.debug("Build: no delta " + debugBuilder() + " [" + debugProject() + "] " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
737
				Policy.debug("Build: no delta " + debugBuilder() + " [" + debugProject() + "] " + project.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
681
			if (Policy.DEBUG_BUILD_DELTA) {
738
			if (Policy.DEBUG_BUILD_DELTA) {
Lines 692-698 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
692
	/**
749
	/**
693
	 * Returns the safe runnable instance for invoking a builder
750
	 * Returns the safe runnable instance for invoking a builder
694
	 */
751
	 */
695
	private ISafeRunnable getSafeRunnable(final int trigger, final Map<String, String> args, final MultiStatus status, final IProgressMonitor monitor) {
752
	private ISafeRunnable getSafeRunnable(final int trigger, final Map<String, String> args, final MultiStatus status, final IProgressMonitor monitor, final InternalBuilder builder) {
696
		return new ISafeRunnable() {
753
		return new ISafeRunnable() {
697
			public void handleException(Throwable e) {
754
			public void handleException(Throwable e) {
698
				if (e instanceof OperationCanceledException) {
755
				if (e instanceof OperationCanceledException) {
Lines 700-717 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
700
						Policy.debug("Build canceled"); //$NON-NLS-1$
757
						Policy.debug("Build canceled"); //$NON-NLS-1$
701
					//just discard built state when a builder cancels, to ensure
758
					//just discard built state when a builder cancels, to ensure
702
					//that it is called again on the very next build.
759
					//that it is called again on the very next build.
703
					currentBuilder.forgetLastBuiltState();
760
					builder.forgetLastBuiltState();
704
					throw (OperationCanceledException) e;
761
					throw (OperationCanceledException) e;
705
				}
762
				}
706
				//ResourceStats.buildException(e);
763
				//ResourceStats.buildException(e);
707
				// don't log the exception....it is already being logged in SafeRunner#run
764
				// don't log the exception....it is already being logged in SafeRunner#run
708
765
709
				//add a generic message to the MultiStatus
766
				//add a generic message to the MultiStatus
710
				String builderName = currentBuilder.getLabel();
767
				String builderName = builder.getLabel();
711
				if (builderName == null || builderName.length() == 0)
768
				if (builderName == null || builderName.length() == 0)
712
					builderName = currentBuilder.getClass().getName();
769
					builderName = builder.getClass().getName();
713
				String pluginId = currentBuilder.getPluginId();
770
				String pluginId = builder.getPluginId();
714
				String message = NLS.bind(Messages.events_builderError, builderName, currentBuilder.getProject().getName());
771
				String message = NLS.bind(Messages.events_builderError, builderName, builder.getProject().getName());
715
				status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e));
772
				status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e));
716
773
717
				//add the exception status to the MultiStatus
774
				//add the exception status to the MultiStatus
Lines 722-734 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
722
			public void run() throws Exception {
779
			public void run() throws Exception {
723
				IProject[] prereqs = null;
780
				IProject[] prereqs = null;
724
				//invoke the appropriate build method depending on the trigger
781
				//invoke the appropriate build method depending on the trigger
725
				if (trigger != IncrementalProjectBuilder.CLEAN_BUILD)
782
				if (trigger == IncrementalProjectBuilder.CLEAN_BUILD) {
726
					prereqs = currentBuilder.build(trigger, args, monitor);
783
				    builder.clean(monitor);
727
				else
784
				} else {
728
					currentBuilder.clean(monitor);
785
				    prereqs = builder.build(trigger, args, monitor);
729
				if (prereqs == null)
786
				}
730
					prereqs = new IProject[0];
787
731
				currentBuilder.setInterestingProjects(prereqs.clone());
788
				if (prereqs == null) prereqs = new IProject[0];
789
790
				builder.setInterestingProjects(prereqs.clone());
732
			}
791
			}
733
		};
792
		};
734
	}
793
	}
Lines 920-928 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
920
	 * to the given project, and false otherwise.
979
	 * to the given project, and false otherwise.
921
	 */
980
	 */
922
	private boolean isInterestingProject(IProject project) {
981
	private boolean isInterestingProject(IProject project) {
923
		if (project.equals(currentBuilder.getProject()))
982
		if (project.equals(currentBuilder.get().getProject()))
924
			return true;
983
			return true;
925
		IProject[] interestingProjects = currentBuilder.getInterestingProjects();
984
		IProject[] interestingProjects = currentBuilder.get().getInterestingProjects();
926
		for (int i = 0; i < interestingProjects.length; i++) {
985
		for (int i = 0; i < interestingProjects.length; i++) {
927
			if (interestingProjects[i].equals(project)) {
986
			if (interestingProjects[i].equals(project)) {
928
				return true;
987
				return true;
Lines 950-956 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
950
			case IncrementalProjectBuilder.FULL_BUILD :
1009
			case IncrementalProjectBuilder.FULL_BUILD :
951
				return true;
1010
				return true;
952
			case IncrementalProjectBuilder.INCREMENTAL_BUILD :
1011
			case IncrementalProjectBuilder.INCREMENTAL_BUILD :
953
				if (currentBuilder.callOnEmptyDelta())
1012
				if (currentBuilder.get().callOnEmptyDelta())
954
					return true;
1013
					return true;
955
				//fall through and check if there is a delta
1014
				//fall through and check if there is a delta
956
		}
1015
		}
Lines 959-978 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
959
		ElementTree oldTree = builder.getLastBuiltTree();
1018
		ElementTree oldTree = builder.getLastBuiltTree();
960
		ElementTree newTree = workspace.getElementTree();
1019
		ElementTree newTree = workspace.getElementTree();
961
		long start = System.currentTimeMillis();
1020
		long start = System.currentTimeMillis();
962
		currentDelta = (DeltaDataTree) deltaTreeCache.getDelta(null, oldTree, newTree);
1021
		currentDelta.set((DeltaDataTree) deltaTreeCache.getDelta(null, oldTree, newTree));
963
		if (currentDelta == null) {
1022
		if (currentDelta.get() == null) {
964
			if (Policy.DEBUG_BUILD_NEEDED) {
1023
			if (Policy.DEBUG_BUILD_NEEDED) {
965
				String message = "Checking if need to build. Starting delta computation between: " + oldTree.toString() + " and " + newTree.toString(); //$NON-NLS-1$ //$NON-NLS-2$
1024
				String message = "Checking if need to build. Starting delta computation between: " + oldTree.toString() + " and " + newTree.toString(); //$NON-NLS-1$ //$NON-NLS-2$
966
				Policy.debug(message);
1025
				Policy.debug(message);
967
			}
1026
			}
968
			currentDelta = newTree.getDataTree().forwardDeltaWith(oldTree.getDataTree(), ResourceComparator.getBuildComparator());
1027
			currentDelta.set(newTree.getDataTree().forwardDeltaWith(oldTree.getDataTree(), ResourceComparator.getBuildComparator()));
969
			if (Policy.DEBUG_BUILD_NEEDED)
1028
			if (Policy.DEBUG_BUILD_NEEDED)
970
				Policy.debug("End delta computation. (" + (System.currentTimeMillis() - start) + "ms)."); //$NON-NLS-1$ //$NON-NLS-2$
1029
				Policy.debug("End delta computation. (" + (System.currentTimeMillis() - start) + "ms)."); //$NON-NLS-1$ //$NON-NLS-2$
971
			deltaTreeCache.cache(null, oldTree, newTree, currentDelta);
1030
			deltaTreeCache.cache(null, oldTree, newTree, currentDelta.get());
972
		}
1031
		}
973
1032
974
		//search for the builder's project
1033
		//search for the builder's project
975
		if (currentDelta.findNodeAt(builder.getProject().getFullPath()) != null) {
1034
		if (currentDelta.get().findNodeAt(builder.getProject().getFullPath()) != null) {
976
			if (Policy.DEBUG_BUILD_NEEDED)
1035
			if (Policy.DEBUG_BUILD_NEEDED)
977
				Policy.debug(toString(builder) + " needs building because of changes in: " + builder.getProject().getName()); //$NON-NLS-1$
1036
				Policy.debug(toString(builder) + " needs building because of changes in: " + builder.getProject().getName()); //$NON-NLS-1$
978
			return true;
1037
			return true;
Lines 981-987 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
981
		//search for builder's interesting projects
1040
		//search for builder's interesting projects
982
		IProject[] projects = builder.getInterestingProjects();
1041
		IProject[] projects = builder.getInterestingProjects();
983
		for (int i = 0; i < projects.length; i++) {
1042
		for (int i = 0; i < projects.length; i++) {
984
			if (currentDelta.findNodeAt(projects[i].getFullPath()) != null) {
1043
			if (currentDelta.get().findNodeAt(projects[i].getFullPath()) != null) {
985
				if (Policy.DEBUG_BUILD_NEEDED)
1044
				if (Policy.DEBUG_BUILD_NEEDED)
986
					Policy.debug(toString(builder) + " needs building because of changes in: " + projects[i].getName()); //$NON-NLS-1$
1045
					Policy.debug(toString(builder) + " needs building because of changes in: " + projects[i].getName()); //$NON-NLS-1$
987
				return true;
1046
				return true;
Lines 1143-1146 public class BuildManager implements ICoreConstants, IManager, ILifecycleListene Link Here
1143
			Policy.log(status);
1202
			Policy.log(status);
1144
		return workspace.getRoot();
1203
		return workspace.getRoot();
1145
	}
1204
	}
1205
	
1206
    public void buildParallel(final int trigger, IProgressMonitor monitor, IBuildConfiguration[] configs) throws CoreException {        
1207
        
1208
        final boolean clean = (trigger == IncrementalProjectBuilder.PARALLEL_CLEAN_BUILD);
1209
        
1210
        long start = System.currentTimeMillis();
1211
        if (clean) {            
1212
            Policy.log(new ResourceStatus(IStatus.INFO, "Starting parallel cleaning of " + configs.length + " projects..."));
1213
        } else {
1214
            Policy.log(new ResourceStatus(IStatus.INFO, "Starting parallel build of " + configs.length + " projects..."));
1215
        }
1216
        final SharedProgressMonitor sharedProgress = new SharedProgressMonitor(Policy.monitorFor(monitor));
1217
        
1218
        List<IProject> projects = new ArrayList<IProject>();
1219
        DirectedGraphs<IProject> directedGraphs = new DirectedGraphs<IProject>();
1220
        for (IBuildConfiguration config : configs) {
1221
            projects.add(config.getProject());
1222
            directedGraphs.addNode(new Node<IProject>(config.getProject()));
1223
        }
1224
1225
        // cleaning does not require building the graph
1226
        if (trigger == IncrementalProjectBuilder.PARALLEL_FULL_BUILD) {
1227
            for (IProject project : projects) {
1228
                if (!project.isAccessible())
1229
                    continue;
1230
                ProjectDescription desc = ((Project)project).internalGetDescription();
1231
                if (desc == null)
1232
                    continue;
1233
                IProject[] refs = desc.getAllReferences(false);
1234
                Node<IProject> node = directedGraphs.getNodeWithContent(project);
1235
                for (IProject referencedProject : refs) {
1236
                    Node<IProject> node2 = directedGraphs.getNodeWithContent(referencedProject);
1237
                    if(node2 != null) {
1238
                        node2.addOutgoingEdge(node);
1239
                    }
1240
                }
1241
            }
1242
        }
1243
        
1244
        hookStartBuild(configs, trigger);
1245
        
1246
        final MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR, Messages.events_errors, null);
1247
        
1248
        if (clean) {
1249
            sharedProgress.beginTask("Cleaning projects in parallel:", projects.size());
1250
        } else {
1251
            sharedProgress.beginTask("Building projects in parallel:", projects.size());
1252
        }
1253
        
1254
        ThreadPoolBuilder threadPoolBuilder = new ThreadPoolBuilder();
1255
        try {           
1256
            IBuildExecutor buildExecutor = new IBuildExecutor() {
1257
                public void executeBuild(IBuildDescription buildDescription, SharedProgressMonitor sharedProgress) {
1258
                    IProgressMonitor progressMonitor = new NullProgressMonitor();
1259
                    try {
1260
                        sharedProgress.addProjectName(buildDescription.getBuildConfiguration().getProject().getName());
1261
                        basicBuild(buildDescription.getBuildConfiguration(), trigger, buildDescription.getBuildContext(), status, progressMonitor);
1262
                    } finally {
1263
                        sharedProgress.removeProjectName(buildDescription.getBuildConfiguration().getProject().getName());
1264
                        sharedProgress.worked(1);
1265
                    }
1266
                }};
1267
                threadPoolBuilder.run(directedGraphs, buildExecutor, sharedProgress);
1268
        } catch (InterruptedException e) {
1269
            status.add(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, Messages.events_errors, e));
1270
        } finally {
1271
            hookEndBuild(trigger);
1272
            long finish = System.currentTimeMillis();
1273
            if (clean) {
1274
                Policy.log(new ResourceStatus(IStatus.INFO, "Finished parallel clean in " + (finish - start) + "ms"));
1275
            } else {
1276
                Policy.log(new ResourceStatus(IStatus.INFO, "Finished parallel build in " + (finish - start) + "ms"));              
1277
            }
1278
            sharedProgress.done();
1279
        } 
1280
    }
1281
1282
    private IncrementalProjectBuilder getParallelBuilder(IBuildConfiguration buildConfiguration, BuildCommand command, int buildSpecIndex, MultiStatus status, IBuildContext buildContext) throws CoreException {
1283
        // always construct a new builder for parallel builds (think about pooling here)
1284
        InternalBuilder result = initializeBuilder(command.getBuilderName(), buildConfiguration, buildSpecIndex, status);
1285
        command.setBuilders(result);
1286
        result.setCommand(command);
1287
        result.setBuildConfig(buildConfiguration);
1288
        result.startupOnInitialize();
1289
        //      }
1290
1291
        if (!validateNature(result, command.getBuilderName())) {
1292
            //skip this builder and null its last built tree because it is invalid
1293
            //if the nature gets added or re-enabled a full build will be triggered
1294
            result.setLastBuiltTree(null);
1295
            return null;
1296
        }
1297
        return (IncrementalProjectBuilder) result;
1298
    }	
1146
}
1299
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildRunnable.java (+52 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial changes to support parallel build
10
 *     Morgan Stanley - [126121] Fixing parallel build concurrency issues
11
*******************************************************************************/
12
package org.eclipse.core.internal.events;
13
14
import java.util.ArrayList;
15
import java.util.List;
16
import java.util.concurrent.BlockingQueue;
17
18
import org.eclipse.core.internal.resources.BuildConfiguration;
19
import org.eclipse.core.resources.IProject;
20
21
// The worker instance that is executed in a ThreadPool worker thread
22
public final class BuildRunnable implements Runnable {
23
	
24
	private final Node<IProject> currentNode;
25
	private final BlockingQueue<Node<IProject>> queue;
26
	private final IBuildExecutor executor;
27
	private final SharedProgressMonitor sharedProgress;
28
29
	protected BuildRunnable(Node<IProject> currentNode, BlockingQueue<Node<IProject>> queue, IBuildExecutor executor, SharedProgressMonitor sharedMonitor) {
30
		this.currentNode = currentNode;
31
		this.queue = queue;
32
		this.executor = executor;
33
		this.sharedProgress = sharedMonitor;
34
	}
35
	
36
	public void run() {			
37
			if (sharedProgress.isCanceled()) {
38
				return;
39
			}			
40
//			System.out.println("start compile " + currentNode.getContent()); //$NON-NLS-1$
41
			BuildDescription buildDescription = new BuildDescription(null, new BuildConfiguration(currentNode.getContent()));
42
			executor.executeBuild(buildDescription, sharedProgress);
43
//			System.out.println("end compile " + currentNode.getContent()); //$NON-NLS-1$
44
			List<Node<IProject>> outgoingNodes = new ArrayList<Node<IProject>>(currentNode.getOutgoingEdges()); 
45
			currentNode.removeAllOutgoingEdges();
46
			for (Node<IProject> node : outgoingNodes) {
47
				if(node.getIncomingEdges().isEmpty()) {
48
					queue.add(node);
49
				}
50
			}
51
	}
52
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/DirectedGraphs.java (+67 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial changes to support parallel build
10
 *******************************************************************************/
11
package org.eclipse.core.internal.events;
12
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.HashSet;
16
import java.util.LinkedHashSet;
17
import java.util.Set;
18
19
/**
20
 * A directed graph holds all nodes. Nodes need not be connected which is why a container object is required
21
 * 
22
 * @author jens
23
 *
24
 */
25
public class DirectedGraphs<T> {
26
	
27
	private Set<Node<T>> nodes;
28
29
	public DirectedGraphs() {
30
		nodes = Collections.synchronizedSet(new HashSet<Node<T>>());
31
	}
32
	
33
	public void addNode(Node<T> node) {
34
		nodes.add(node);
35
	}
36
37
	public void removeNode(Node<T> node) {
38
		nodes.remove(node);
39
	}
40
	
41
	public void addAll(Collection<Node<T>> nodesToBeAdded) {
42
		nodes.addAll(nodesToBeAdded);
43
	}
44
	
45
	public Node<T> getNodeWithContent(T content) {
46
		for (Node<T> node : nodes) {
47
			if(content.equals(node.getContent())) {
48
				return node;
49
			}
50
		}
51
		return null;
52
	}
53
	
54
	public synchronized Set<Node<T>> getRootNodes() {
55
		Set<Node<T>> set = new LinkedHashSet<Node<T>>();
56
		for (Node<T> node : nodes) {
57
			if(node.getIncomingEdges().isEmpty()) {
58
				set.add(node);
59
			}
60
		}
61
		return set;
62
	}
63
	
64
	public boolean isEmtpy() {
65
		return nodes.isEmpty();
66
	}
67
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/IBuildExecutor.java (+23 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial changes to support parallel build
10
 *******************************************************************************/
11
package org.eclipse.core.internal.events;
12
13
import org.eclipse.core.resources.IBuildDescription;
14
15
16
/**
17
 * 
18
 */
19
public interface IBuildExecutor {
20
	
21
	public void executeBuild(IBuildDescription buildDescription, SharedProgressMonitor sharedProgress);
22
23
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/Node.java (+138 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial changes to support parallel build
10
 *******************************************************************************/
11
package org.eclipse.core.internal.events;
12
13
import java.text.MessageFormat;
14
15
import java.util.Iterator;
16
import java.util.LinkedHashSet;
17
import java.util.Set;
18
19
/**
20
 * A simple node object having references to other node objects 
21
 *
22
 * @param <T>
23
 */
24
public class Node<T> {
25
	
26
	private Set<Node<T>> incomingEdges;
27
28
	private Set<Node<T>> outgoingEdges;
29
	
30
	private T content;
31
	
32
	public Node(T content) {
33
		this.content = content;
34
		incomingEdges = new LinkedHashSet<Node<T>>(); 
35
		outgoingEdges = new LinkedHashSet<Node<T>>(); 
36
	}
37
	
38
	public T getContent() {
39
		return content;
40
	}
41
42
	public void setContent(T content) {
43
		this.content = content;
44
	}
45
46
	public synchronized Set<Node<T>> getIncomingEdges() {
47
		return incomingEdges;
48
	}
49
50
	public synchronized Set<Node<T>> getOutgoingEdges() {
51
		return outgoingEdges;
52
	}
53
54
	public synchronized void addIncomingEdge(Node<T> node) {
55
		if(!incomingEdges.contains(node)) {
56
			incomingEdges.add(node);
57
			node.addOutgoingEdge(this);
58
		}
59
	}
60
61
	public synchronized void addOutgoingEdge(Node<T> node) {
62
		if(!outgoingEdges.contains(node)) {
63
			outgoingEdges.add(node);
64
			node.addIncomingEdge(this);
65
		}
66
	}
67
	
68
	public synchronized void removeOutgoingEdge(Node<T> node) {
69
		if(outgoingEdges.contains(node)) {
70
			outgoingEdges.remove(node);
71
			node.removeIncomingEdge(this);
72
		}
73
	}
74
	
75
	public synchronized void removeIncomingEdge(Node<T> node) {
76
		if(incomingEdges.contains(node)) {
77
			incomingEdges.remove(node);
78
			node.removeOutgoingEdge(this);
79
		}
80
	}
81
82
	public synchronized void removeAllOutgoingEdges() {
83
		for (Iterator<Node<T>> iterator = outgoingEdges.iterator(); iterator.hasNext();) {
84
			Node<T> node = iterator.next();
85
			node.internalRemoveIncomingEdge(this);
86
			iterator.remove();
87
		}
88
	}
89
90
	public synchronized void removeAllIncomingEdges() {
91
		for (Iterator<Node<T>> iterator = incomingEdges.iterator(); iterator.hasNext();) {
92
			Node<T> node = iterator.next();
93
			node.internalRemoveOutgoingEdge(this);
94
			iterator.remove();
95
		}
96
	}
97
98
	synchronized void internalRemoveOutgoingEdge(Node<T> node) {
99
		outgoingEdges.remove(node);
100
	}
101
102
	synchronized void internalRemoveIncomingEdge(Node<T> node) {
103
		incomingEdges.remove(node);
104
	}
105
106
	@Override
107
	public int hashCode() {
108
		final int prime = 31;
109
		int result = 1;
110
		result = prime * result + ((content == null) ? 0 : content.hashCode());
111
		return result;
112
	}
113
114
	@Override
115
	public boolean equals(Object obj) {
116
		if (this == obj)
117
			return true;
118
		if (obj == null)
119
			return false;
120
		if (getClass() != obj.getClass())
121
			return false;
122
		Node other = (Node) obj;
123
		if (content == null) {
124
			if (other.content != null)
125
				return false;
126
		} else if (!content.equals(other.content))
127
			return false;
128
		return true;
129
	}
130
131
	@Override
132
	public String toString() {
133
		return MessageFormat.format("Node [content={0}]", content); //$NON-NLS-1$
134
	}
135
136
	
137
	
138
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/SharedProgressMonitor.java (+89 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Morgan Stanley - [126121] Fixing parallel build concurrency issues
10
 *******************************************************************************/
11
package org.eclipse.core.internal.events;
12
13
import java.util.LinkedHashSet;
14
import java.util.Set;
15
16
import org.eclipse.core.runtime.IProgressMonitor;
17
18
/**
19
 * Simple thread-safe {@link IProgressMonitor} wrapper used by the parallel builder to add/remove names of
20
 * projects that are actually building.
21
 */
22
public class SharedProgressMonitor implements IProgressMonitor {
23
24
	private final IProgressMonitor progressMonitor;
25
	private final Set<String> projectNames = new LinkedHashSet<String>();
26
	private String taskNamePrefix = "";
27
	
28
	public SharedProgressMonitor(IProgressMonitor progressMonitor) {
29
		this.progressMonitor = progressMonitor;
30
	}
31
32
	public synchronized void beginTask(String name, int totalWork) {
33
		taskNamePrefix = name;
34
		progressMonitor.beginTask(name, totalWork);
35
	}
36
37
	public synchronized void done() {
38
		progressMonitor.done();
39
	}
40
41
	public synchronized void internalWorked(double work) {
42
		progressMonitor.internalWorked(work);
43
	}
44
45
	public boolean isCanceled() {
46
		return progressMonitor.isCanceled();
47
	}
48
49
	public synchronized void setCanceled(boolean value) {
50
		progressMonitor.setCanceled(value);
51
	}
52
53
	public synchronized void setTaskName(String name) {
54
		progressMonitor.setTaskName(name);
55
	}
56
57
	public synchronized void subTask(String name) {
58
		progressMonitor.subTask(name);
59
	}
60
61
	public synchronized void worked(int work) {
62
		progressMonitor.worked(work);
63
	}
64
	
65
	public synchronized void addProjectName(String projName) {
66
		projectNames.add(projName);
67
		setTaskName(taskNamePrefix + " " + getProjectNames(projectNames));
68
	}
69
	
70
	public synchronized void removeProjectName(String projName) {
71
		projectNames.remove(projName);
72
		setTaskName(taskNamePrefix + " " + getProjectNames(projectNames));
73
	}	
74
	
75
	private static String getProjectNames(Set<String> projectNames) {
76
		StringBuilder builder = new StringBuilder("[");
77
		boolean first = true;
78
		for (String name : projectNames) {
79
			if (first) {
80
				first = false;
81
			} else {
82
				builder.append(", ");
83
			}
84
			builder.append(name);
85
		}
86
		builder.append("]");
87
		return builder.toString();
88
	}
89
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/events/ThreadPoolBuilder.java (+50 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Jens Kuebler - [126121] - Initial changes to support parallel build
10
 *     Morgan Stanley - [126121] Fixing parallel build concurrency issues
11
 *******************************************************************************/
12
package org.eclipse.core.internal.events;
13
14
import java.util.concurrent.ArrayBlockingQueue;
15
import java.util.concurrent.BlockingQueue;
16
import java.util.concurrent.ExecutorService;
17
import java.util.concurrent.Executors;
18
import java.util.concurrent.TimeUnit;
19
20
import org.eclipse.core.resources.IProject;
21
22
public class ThreadPoolBuilder {
23
	
24
	private ExecutorService threadPool;
25
	
26
	private BlockingQueue<Node<IProject>> queue;
27
28
	public ThreadPoolBuilder() {
29
		final int threadNum = Runtime.getRuntime().availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() - 1 : 1;
30
		threadPool = Executors.newFixedThreadPool(threadNum);
31
		queue = new ArrayBlockingQueue<Node<IProject>>(6000);
32
	}
33
	
34
	public void run(DirectedGraphs<IProject> directedGraphs, IBuildExecutor runnable, SharedProgressMonitor sharedProgress) throws InterruptedException {
35
//		System.out.println("ThreadPool started...");
36
		queue.addAll(directedGraphs.getRootNodes());
37
		while (!threadPool.isShutdown()) {
38
			if(directedGraphs.isEmtpy() || sharedProgress.isCanceled()) {
39
				threadPool.shutdown();
40
			} else {
41
				Node<IProject>nodeToCompile = queue.take();
42
				directedGraphs.removeNode((Node<IProject>) nodeToCompile);
43
				threadPool.execute(new BuildRunnable(nodeToCompile, queue, runnable, sharedProgress));
44
			}
45
		}
46
		// blocking the main builder thread (Worker-N) until all the threads finishes 
47
		threadPool.awaitTermination(60, TimeUnit.SECONDS);
48
//		System.out.println("ThreadPool finished...");
49
	}
50
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IBuildDescription.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.resources;
12
13
/**
14
 * 
15
 */
16
public interface IBuildDescription {
17
	
18
	IBuildContext getBuildContext();
19
	
20
	IBuildConfiguration getBuildConfiguration();
21
22
}
(-)a/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IncrementalProjectBuilder.java (-1 / +8 lines)
Lines 11-16 Link Here
11
 * Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule
11
 * Anton Leherbauer (Wind River) - [305858] Allow Builder to return null rule
12
 * James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule()
12
 * James Blackburn (Broadcom) - [306822] Provide Context for Builder getRule()
13
 * Broadcom Corporation - build configurations and references
13
 * Broadcom Corporation - build configurations and references
14
 * Jens Kuebler - [126121] - Initial changes to support parallel build
15
 * Morgan Stanley - [126121] Adding support for parallel clean build
14
 *******************************************************************************/
16
 *******************************************************************************/
15
package org.eclipse.core.resources;
17
package org.eclipse.core.resources;
16
18
Lines 50-55 public abstract class IncrementalProjectBuilder extends InternalBuilder implemen Link Here
50
	 * @see IWorkspace#build(int, IProgressMonitor)
52
	 * @see IWorkspace#build(int, IProgressMonitor)
51
	 */
53
	 */
52
	public static final int FULL_BUILD = 6;
54
	public static final int FULL_BUILD = 6;
55
	
56
    public static final int PARALLEL_FULL_BUILD = 7;
57
    
53
	/**
58
	/**
54
	 * Build kind constant (value 9) indicating an automatic build request.  When
59
	 * Build kind constant (value 9) indicating an automatic build request.  When
55
	 * autobuild is turned on, these builds are triggered automatically whenever
60
	 * autobuild is turned on, these builds are triggered automatically whenever
Lines 84-89 public abstract class IncrementalProjectBuilder extends InternalBuilder implemen Link Here
84
	 * @since 3.0
89
	 * @since 3.0
85
	 */
90
	 */
86
	public static final int CLEAN_BUILD = 15;
91
	public static final int CLEAN_BUILD = 15;
92
	
93
	public static final int PARALLEL_CLEAN_BUILD = 16;
87
94
88
	/**
95
	/**
89
	 * Runs this builder in the specified manner. Subclasses should implement
96
	 * Runs this builder in the specified manner. Subclasses should implement
Lines 451-457 public abstract class IncrementalProjectBuilder extends InternalBuilder implemen Link Here
451
	 * @since 3.6
458
	 * @since 3.6
452
	 */
459
	 */
453
	public ISchedulingRule getRule(int kind, Map<String,String> args) {
460
	public ISchedulingRule getRule(int kind, Map<String,String> args) {
454
		return getRule();
461
		return getProject();
455
	}
462
	}
456
463
457
	/**
464
	/**

Return to bug 126121