Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMickael Istria2018-03-19 21:28:08 +0000
committerMickael Istria2018-09-10 08:55:14 +0000
commit749e6f86b20add3c4fa8193fea1a613d6b0a897b (patch)
treedd39630f4f7ac8813f899ea373172f2069218db3
parent137440659e5f6de2b611e18488e240eb603d47e1 (diff)
downloadeclipse.jdt.core-749e6f86b20add3c4fa8193fea1a613d6b0a897b.tar.gz
eclipse.jdt.core-749e6f86b20add3c4fa8193fea1a613d6b0a897b.tar.xz
eclipse.jdt.core-749e6f86b20add3c4fa8193fea1a613d6b0a897b.zip
Bug 531554 - Pref to allow null scheduling rule for Java Builder
Also relax rules for several other WorkspaceRunnable, so it allows Workspace to enable parallel builds even when some JDT projects are present. Change-Id: Idae1a746077f9d380eb67fc7c3345aa072bab351 Signed-off-by: Mickael Istria <mistria@redhat.com>
-rw-r--r--org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/env/BuildEnv.java240
-rw-r--r--org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/generatedfile/GeneratedSourceFolderManager.java2
-rw-r--r--org.eclipse.jdt.core.tests.builder/plugin.xml10
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java1
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParallelBuildTests.java100
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TimeStampBuilder.java64
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java7
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java3
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java12
9 files changed, 321 insertions, 118 deletions
diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/env/BuildEnv.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/env/BuildEnv.java
index c4da45e2d8..c8c022c482 100644
--- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/env/BuildEnv.java
+++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/env/BuildEnv.java
@@ -18,7 +18,12 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
@@ -38,45 +43,52 @@ import org.eclipse.jdt.apt.core.internal.util.Visitors.AnnotationVisitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.BuildContext;
-import org.eclipse.jdt.core.dom.*;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
+import org.eclipse.jdt.core.dom.Annotation;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+
import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.PackageDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
public class BuildEnv extends AbstractCompilationEnv
-{
+{
private boolean _hasRaisedErrors = false;
- private final BuildFilerImpl _filer;
+ private final BuildFilerImpl _filer;
/**
* Set of strings that indicate new type dependencies introduced on the file
* each string is a fully-qualified type name.
*/
private Set<String> _typeDependencies = new HashSet<>();
-
+
/**
- * Indicates whether we are in batch mode or not. This gets flipped only
- * during build and could be flipped back and forth.
+ * Indicates whether we are in batch mode or not. This gets flipped only
+ * during build and could be flipped back and forth.
*/
private boolean _batchMode = false; // off by default.
- /**
+ /**
* Holds all the files that contains annotation that are to be processed during build.
- * If we are not in batch mode, <code>super._file</code> holds the file
- * being processed at the time.
- */
+ * If we are not in batch mode, <code>super._file</code> holds the file
+ * being processed at the time.
+ */
private BuildContext[] _filesWithAnnotation = null;
-
+
/**
* These are files that are part of a build but does not have annotations on it.
- * During batch mode processing, these files still also need to be included.
+ * During batch mode processing, these files still also need to be included.
*/
private BuildContext[] _additionFiles = null;
- /**
+ /**
* This is intialized when <code>_batchMode</code> is set to be <code>true</code> or
* when batch processing is expected. <p>
* It is also set in build mode for perf reason rather than parsing and resolving
@@ -85,29 +97,29 @@ public class BuildEnv extends AbstractCompilationEnv
*/
private CompilationUnit[] _astRoots = null;
private List<MarkerInfo> _markerInfos = null;
-
+
/**
* Constructor for creating a processor environment used during build.
* @param filesWithAnnotations
* @param additionalFiles
* @param units
* @param javaProj
- * @param isTestCode
+ * @param isTestCode
* @param phase
*/
BuildEnv(
final BuildContext[] filesWithAnnotations,
final BuildContext[] additionalFiles,
final IJavaProject javaProj, boolean isTestCode) {
-
+
super(null, null, javaProj, Phase.BUILD, isTestCode);
_filer = new BuildFilerImpl(this);
_filesWithAnnotation = filesWithAnnotations;
_additionFiles = additionalFiles;
_problems = new ArrayList<>();
_markerInfos = new ArrayList<>();
-
- if (AptPlugin.DEBUG_COMPILATION_ENV) AptPlugin.trace(
+
+ if (AptPlugin.DEBUG_COMPILATION_ENV) AptPlugin.trace(
"constructed " + this + " for " + _filesWithAnnotation.length + " files"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@@ -127,12 +139,12 @@ public class BuildEnv extends AbstractCompilationEnv
@Override
public TypeDeclaration getTypeDeclaration(String name)
{
- checkValid();
+ checkValid();
TypeDeclaration decl = super.getTypeDeclaration(name);
-
- if (!_batchMode)
+
+ if (!_batchMode)
addTypeDependency(name);
-
+
return decl;
}
@@ -142,7 +154,7 @@ public class BuildEnv extends AbstractCompilationEnv
*/
public boolean hasRaisedErrors(){
return _hasRaisedErrors;
- }
+ }
public static InputStreamReader getFileReader( final IFile file ) throws IOException, CoreException {
return new InputStreamReader(getInputStream(file), file.getCharset());
@@ -167,7 +179,7 @@ public class BuildEnv extends AbstractCompilationEnv
*/
@Override
public void close(){
- if( isClosed() )
+ if( isClosed() )
return;
_markerInfos = null;
_astRoot = null;
@@ -175,13 +187,13 @@ public class BuildEnv extends AbstractCompilationEnv
_astRoots = null;
_filesWithAnnotation = null;
_problems = null;
- _modelCompUnit2astCompUnit.clear();
+ _modelCompUnit2astCompUnit.clear();
_hasRaisedErrors = false;
super.close();
}
-
+
/**
- *
+ *
* @param resource null to indicate current resource
* @param start the starting offset of the marker
* @param end -1 to indicate unknow ending offset.
@@ -190,21 +202,21 @@ public class BuildEnv extends AbstractCompilationEnv
* @param line the line number of where the marker should be
*/
@Override
- void addMessage(IFile resource,
- int start,
+ void addMessage(IFile resource,
+ int start,
int end,
- Severity severity,
- String msg,
+ Severity severity,
+ String msg,
int line,
String[] arguments)
{
checkValid();
-
+
if( resource == null )
resource = getFile();
-
+
_hasRaisedErrors |= severity == MessagerImpl.Severity.ERROR;
-
+
// Eclipse doesn't support INFO-level IProblems, so we send them to the log instead.
if ( severity == Severity.INFO) {
StringBuilder sb = new StringBuilder();
@@ -236,69 +248,69 @@ public class BuildEnv extends AbstractCompilationEnv
AptPlugin.log(status);
return;
}
-
+
if( resource == null ){
assert _batchMode : "not in batch mode but don't know about current resource"; //$NON-NLS-1$
addMarker(start, end, severity, msg, line, arguments);
}
- else
+ else
addProblem(resource, start, end, severity, msg, line, arguments);
}
-
+
private void addProblem(
- IFile resource,
- int start,
+ IFile resource,
+ int start,
int end,
- Severity severity,
- String msg,
+ Severity severity,
+ String msg,
int line,
String[] arguments)
- {
-
+ {
+
APTProblem problem = createProblem(resource, start, end, severity, msg, line, arguments);
_problems.add(problem);
}
-
+
private void addMarker(
- int start,
+ int start,
int end,
- Severity severity,
- String msg,
+ Severity severity,
+ String msg,
int line,
String[] arguments)
- {
-
+ {
+
// Note that the arguments are ignored -- no quick-fix for markers.
_markerInfos.add(new MarkerInfo(start, end, severity, msg, line));
}
-
+
@Override
public Map<String, AnnotationTypeDeclaration> getAnnotationTypes()
{
checkValid();
- assert _astRoot != null && _file != null && !_batchMode :
+ assert _astRoot != null && _file != null && !_batchMode :
"operation not available under batch mode."; //$NON-NLS-1$
return super.getAnnotationTypes();
}
-
+
/**
* Return all annotations at declaration level within all compilation unit(s)
- * associated with this environment. All the files associated with this environment will
+ * associated with this environment. All the files associated with this environment will
* be parsed and resolved for all declaration level elements at the return of this call.
- *
+ *
* @param file2Annotations populated by this method to map files to the annotation types
* if contains. May be null.
* @return the map containing all annotation types found within this environment.
*/
public Map<String, AnnotationTypeDeclaration> getAllAnnotationTypes(
final Map<BuildContext, Set<AnnotationTypeDeclaration>> file2Annotations) {
-
+
checkValid();
- if( _filesWithAnnotation == null )
+ if( _filesWithAnnotation == null )
return getAnnotationTypes();
-
+
final List<Annotation> instances = new ArrayList<>();
- final Map<String, AnnotationTypeDeclaration> decls =
+ final Map<String, AnnotationTypeDeclaration> decls =
new HashMap<>();
final AnnotationVisitor visitor = new AnnotationVisitor(instances);
for( int astIndex=0, len=_astRoots.length; astIndex<len; astIndex++ ){
@@ -306,13 +318,13 @@ public class BuildEnv extends AbstractCompilationEnv
System.err.println();
_astRoots[astIndex].accept(visitor);
final Set<AnnotationTypeDeclaration> perFileAnnos = new HashSet<>();
-
+
for (int instanceIndex=0, size = instances.size(); instanceIndex < size; instanceIndex++) {
final Annotation instance = instances.get(instanceIndex);
final ITypeBinding annoType = instance.resolveTypeBinding();
if (annoType == null)
continue;
- final TypeDeclarationImpl decl =
+ final TypeDeclarationImpl decl =
Factory.createReferenceType(annoType, this);
if (decl != null && decl.kind() == EclipseMirrorObject.MirrorKind.TYPE_ANNOTATION){
final AnnotationTypeDeclaration annoDecl = (AnnotationTypeDeclaration)decl;
@@ -324,37 +336,37 @@ public class BuildEnv extends AbstractCompilationEnv
file2Annotations.put(_filesWithAnnotation[astIndex], perFileAnnos);
visitor.reset();
}
-
+
return decls;
}
/**
* @return - the extra type dependencies for the files under compilation
*/
- public Set<String> getTypeDependencies() { return _typeDependencies; }
-
+ public Set<String> getTypeDependencies() { return _typeDependencies; }
+
/**
- * Switch to batch processing mode.
- * Note: Call to this method will cause all files associated with this environment to be
+ * Switch to batch processing mode.
+ * Note: Call to this method will cause all files associated with this environment to be
* read and parsed.
*/
- public void beginBatchProcessing(){
+ public void beginBatchProcessing(){
if( _phase != Phase.BUILD )
throw new IllegalStateException("No batch processing outside build."); //$NON-NLS-1$
-
+
if( _batchMode ) return;
checkValid();
-
+
_batchMode = true;
_file = null;
_astRoot = null;
}
-
+
public void completedBatchProcessing(){
postMarkers();
completedProcessing();
}
-
+
void createASTs(BuildContext[] cpResults){
final int len = cpResults.length;
final ICompilationUnit[] units = new ICompilationUnit[len];
@@ -366,17 +378,17 @@ public class BuildEnv extends AbstractCompilationEnv
createASTs(_javaProject, units, _requestor = new CallbackRequestor(units));
}
- public void beginFileProcessing(BuildContext result){
+ public void beginFileProcessing(BuildContext result){
if( result == null )
throw new IllegalStateException("missing compilation result"); //$NON-NLS-1$
_batchMode = false;
final IFile file = result.getFile();
if( file.equals(_file) ) // this is a no-op
return;
-
+
_astRoot = null;
_file = null;
-
+
// need to match up the file with the ast.
if( _filesWithAnnotation != null ){
for( int i=0, len=_filesWithAnnotation.length; i<len; i++ ){
@@ -386,37 +398,37 @@ public class BuildEnv extends AbstractCompilationEnv
}
}
}
-
+
if( _file == null || _astRoot == null)
throw new IllegalStateException(
"file " + //$NON-NLS-1$
- file.getName() +
+ file.getName() +
" is not in the list to be processed."); //$NON-NLS-1$
}
-
+
public void completedFileProcessing(){
completedProcessing();
}
-
+
@Override
protected void completedProcessing(){
_problems.clear();
_typeDependencies.clear();
super.completedProcessing();
}
-
+
@Override
public List<? extends CategorizedProblem> getProblems(){
if( !_problems.isEmpty() )
EnvUtil.updateProblemLength(_problems, getAstCompilationUnit());
return _problems;
}
-
+
// Implementation for EclipseAnnotationProcessorEnvironment
@Override
public CompilationUnit getAST()
{
- if( _batchMode )
+ if( _batchMode )
return null;
return _astRoot;
}
@@ -424,12 +436,12 @@ public class BuildEnv extends AbstractCompilationEnv
@Override
public void addTypeDependency(final String fullyQualifiedTypeName )
{
- if(!_batchMode){
+ if(!_batchMode){
_typeDependencies.add( fullyQualifiedTypeName );
}
}
// End of implementation for EclipseAnnotationProcessorEnvironment
-
+
/**
* Include all the types from all files, files with and without annotations on it
* if we are in batch mode. Otherwise, just the types from the file that's currently
@@ -443,15 +455,15 @@ public class BuildEnv extends AbstractCompilationEnv
final List<AbstractTypeDeclaration> typeDecls = new ArrayList<>();
for( int i=0, len=_astRoots.length; i<len; i++ )
typeDecls.addAll( _astRoots[i].types() );
-
+
getTypeDeclarationsFromAdditionFiles(typeDecls);
-
+
return typeDecls;
}
-
+
private void getTypeDeclarationsFromAdditionFiles(List<AbstractTypeDeclaration> typeDecls){
if( _additionFiles == null || _additionFiles.length == 0 ) return;
-
+
final int len = _additionFiles.length;
final ICompilationUnit[] units = new ICompilationUnit[len];
for( int i=0; i<len; i++ ){
@@ -461,7 +473,7 @@ public class BuildEnv extends AbstractCompilationEnv
}
BaseRequestor r = new BaseRequestor(units);
createASTs(_javaProject, units, r);
-
+
CompilationUnit[] asts = r.asts;
for( CompilationUnit ast : asts ){
if( ast != null ){
@@ -469,19 +481,19 @@ public class BuildEnv extends AbstractCompilationEnv
}
}
}
-
+
@Override
protected Map<ASTNode, List<Annotation>> getASTNodesWithAnnotations()
{
if( !_batchMode )
return super.getASTNodesWithAnnotations();
final Map<ASTNode, List<Annotation>> astNode2Anno = new HashMap<>();
- final AnnotatedNodeVisitor visitor = new AnnotatedNodeVisitor(astNode2Anno);
+ final AnnotatedNodeVisitor visitor = new AnnotatedNodeVisitor(astNode2Anno);
for( int i=0, len=_astRoots.length; i<len; i++ )
_astRoots[i].accept( visitor );
return astNode2Anno;
}
-
+
@Override
protected IFile getFileForNode(final ASTNode node)
{
@@ -494,12 +506,12 @@ public class BuildEnv extends AbstractCompilationEnv
}
throw new IllegalStateException();
}
-
+
/**
* Go through the list of compilation unit in this environment and looking for
* the declaration node of the given binding.
- * @param binding
- * @return the compilation unit that defines the given binding or null if no
+ * @param binding
+ * @return the compilation unit that defines the given binding or null if no
* match is found.
*/
@Override
@@ -507,7 +519,7 @@ public class BuildEnv extends AbstractCompilationEnv
{
if( !_batchMode )
return super.searchLocallyForBinding(binding);
-
+
for( int i=0, len=_astRoots.length; i<len; i++ ){
ASTNode node = _astRoots[i].findDeclaringNode(binding);
if( node != null)
@@ -515,12 +527,12 @@ public class BuildEnv extends AbstractCompilationEnv
}
return null;
}
-
+
/**
* Go through the list of compilation unit in this environment and looking for
* the declaration node of the given binding.
- * @param binding
- * @return the compilation unit that defines the given binding or null if no
+ * @param binding
+ * @return the compilation unit that defines the given binding or null if no
* match is found.
*/
@Override
@@ -528,7 +540,7 @@ public class BuildEnv extends AbstractCompilationEnv
{
if( !_batchMode )
return super.searchLocallyForIFile(binding);
-
+
for( int i=0, len=_astRoots.length; i<len; i++ ){
ASTNode node = _astRoots[i].findDeclaringNode(binding);
if( node != null)
@@ -536,7 +548,7 @@ public class BuildEnv extends AbstractCompilationEnv
}
return null;
}
-
+
/**
* @param file
* @return the compilation unit associated with the given file.
@@ -546,7 +558,7 @@ public class BuildEnv extends AbstractCompilationEnv
@Override
public CompilationUnit getASTFrom(final IFile file)
{
- if( file == null )
+ if( file == null )
return null;
else if( file.equals(_file) )
return _astRoot;
@@ -558,15 +570,15 @@ public class BuildEnv extends AbstractCompilationEnv
}
return null;
}
-
+
/**
* @return the current ast being processed if in per-file mode.
* If in batch mode, one of the asts being processed (no guarantee which
- * one will be returned.
+ * one will be returned.
*/
@Override
protected AST getCurrentDietAST(){
-
+
if( _astRoot != null )
return _astRoot.getAST();
else{
@@ -575,7 +587,7 @@ public class BuildEnv extends AbstractCompilationEnv
return _astRoots[0].getAST();
}
}
-
+
void postMarkers()
{
if( _markerInfos == null || _markerInfos.size() == 0 )
@@ -586,8 +598,8 @@ public class BuildEnv extends AbstractCompilationEnv
final IWorkspaceRunnable runnable = new IWorkspaceRunnable(){
@Override
public void run(IProgressMonitor monitor)
- {
- for( MarkerInfo markerInfo : _markerInfos ){
+ {
+ for( MarkerInfo markerInfo : _markerInfos ){
try{
final IMarker marker = _javaProject.getProject().createMarker(AptPlugin.APT_BATCH_PROCESSOR_PROBLEM_MARKER);
markerInfo.copyIntoMarker(marker);
@@ -599,7 +611,7 @@ public class BuildEnv extends AbstractCompilationEnv
}
};
IWorkspace ws = _javaProject.getProject().getWorkspace();
- ws.run(runnable, null);
+ ws.run(runnable, _javaProject.getProject(), IWorkspace.AVOID_UPDATE, null);
}
catch(CoreException e){
AptPlugin.log(e, "Failed to post markers"); //$NON-NLS-1$
@@ -608,17 +620,17 @@ public class BuildEnv extends AbstractCompilationEnv
_markerInfos.clear();
}
}
-
+
public BuildContext[] getFilesWithAnnotation()
{
return _filesWithAnnotation;
}
-
+
public BuildContext[] getFilesWithoutAnnotation()
{
return _additionFiles;
}
-
+
private class CallbackRequestor extends BaseRequestor {
CallbackRequestor(ICompilationUnit[] parseUnits) {
super(parseUnits);
@@ -629,7 +641,7 @@ public class BuildEnv extends AbstractCompilationEnv
// then assign the asts, then begin dispatch
_astRoots = asts;
_callback.run(BuildEnv.this);
- }
+ }
}
-
+
}
diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/generatedfile/GeneratedSourceFolderManager.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/generatedfile/GeneratedSourceFolderManager.java
index 697c1b2dd2..f709eafa6c 100644
--- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/generatedfile/GeneratedSourceFolderManager.java
+++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/generatedfile/GeneratedSourceFolderManager.java
@@ -488,7 +488,7 @@ public class GeneratedSourceFolderManager {
};
IWorkspace ws = ResourcesPlugin.getWorkspace();
try{
- ws.run(runnable, ws.getRoot(), IWorkspace.AVOID_UPDATE, null);
+ ws.run(runnable, srcFolder.getProject(), IWorkspace.AVOID_UPDATE, null);
}catch(CoreException e){
AptPlugin.log(e, "Runnable for deleting old generated source folder " + srcFolder.getName() + " failed."); //$NON-NLS-1$ //$NON-NLS-2$
}
diff --git a/org.eclipse.jdt.core.tests.builder/plugin.xml b/org.eclipse.jdt.core.tests.builder/plugin.xml
index bf08c103ed..a2cf6324a2 100644
--- a/org.eclipse.jdt.core.tests.builder/plugin.xml
+++ b/org.eclipse.jdt.core.tests.builder/plugin.xml
@@ -24,4 +24,14 @@
<managedMarker markerType="org.eclipse.jdt.core.tests.compile.problem"/>
</compilationParticipant>
</extension>
+ <extension
+ id="TimeStampBuilder"
+ point="org.eclipse.core.resources.builders">
+ <builder
+ hasNature="false">
+ <run
+ class="org.eclipse.jdt.core.tests.builder.TimeStampBuilder">
+ </run>
+ </builder>
+ </extension>
</plugin>
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
index 277a08ab21..e2451de87e 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
@@ -536,6 +536,7 @@ public class BuilderTests extends TestCase {
TestAttributeBuilderTests.class,
Bug530366Test.class,
Bug531382Test.class,
+ ParallelBuildTests.class
};
if ((AbstractCompilerTest.getPossibleComplianceLevels() & AbstractCompilerTest.F_1_5) != 0) {
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParallelBuildTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParallelBuildTests.java
new file mode 100644
index 0000000000..d964ae6da7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParallelBuildTests.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mickael Istria (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.builder;
+
+import java.util.Collections;
+
+import org.eclipse.core.internal.events.BuildCommand;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspaceDescription;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.core.builder.JavaBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParallelBuildTests extends BuilderTests {
+
+ private int initialMaxParallelBuilds;
+
+ public ParallelBuildTests(String name) {
+ super(name);
+ }
+
+ public static junit.framework.Test suite() {
+ return buildTestSuite(ParallelBuildTests.class);
+ }
+
+ @Before
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ TimeStampBuilder.clear();
+ this.initialMaxParallelBuilds = env.getWorkspace().getDescription().getMaxConcurrentBuilds();
+ InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID).putBoolean(JavaBuilder.PREF_NULL_SCHEDULING_RULE, true);
+ }
+
+ @After
+ @Override
+ protected void tearDown() throws Exception {
+ setMaxParallelBuilds(this.initialMaxParallelBuilds);
+ InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID).remove(JavaBuilder.PREF_NULL_SCHEDULING_RULE);
+ super.tearDown();
+ }
+
+ @Test
+ public void testJDTBuildAllowParallelBuildsForOtherProjects() throws CoreException {
+ IProject javaProject1 = env.getProject(env.addProject(getClass().getSimpleName() + "_javaProject1"));
+ addBuilder(javaProject1.getProject());
+ //
+ IProject javaProject2 = env.getProject(env.addProject(getClass().getSimpleName() + "_javaProject2"));
+ env.addRequiredProject(javaProject2.getFullPath(), javaProject1.getFullPath());
+ addBuilder(javaProject2.getProject());
+ //
+ IProject rawProject1 = env.getWorkspace().getRoot().getProject(getClass().getSimpleName() + System.currentTimeMillis());
+ rawProject1.create(new NullProgressMonitor());
+ rawProject1.open(new NullProgressMonitor());
+ addBuilder(rawProject1);
+ IProject rawProject2 = env.getWorkspace().getRoot().getProject(getClass().getSimpleName() + System.currentTimeMillis());
+ rawProject2.create(new NullProgressMonitor());
+ rawProject2.open(new NullProgressMonitor());
+ addBuilder(rawProject2);
+ setMaxParallelBuilds(3);
+
+ env.fullBuild();
+ // verify that rawProject could build in parallel
+ assertTrue(TimeStampBuilder.start(rawProject1) < TimeStampBuilder.end(rawProject2));
+ assertTrue(TimeStampBuilder.start(rawProject2) < TimeStampBuilder.end(rawProject1));
+ }
+
+ private void setMaxParallelBuilds(int n) throws CoreException {
+ IWorkspaceDescription desc = env.getWorkspace().getDescription();
+ desc.setMaxConcurrentBuilds(n);
+ env.getWorkspace().setDescription(desc);
+ }
+
+ private void addBuilder(IProject project) throws CoreException {
+ IProjectDescription desc1 = project.getDescription();
+ ICommand[] newCommands = new ICommand[desc1.getBuildSpec().length + 1];
+ System.arraycopy(desc1.getBuildSpec(), 0, newCommands, 0, desc1.getBuildSpec().length);
+ BuildCommand builderCommand = new BuildCommand();
+ builderCommand.setBuilderName(TimeStampBuilder.ID);
+ builderCommand.setArguments(Collections.singletonMap(TimeStampBuilder.PAUSE_DURATION, Integer.toString(1000)));
+ newCommands[newCommands.length - 1] = builderCommand;
+ desc1.setBuildSpec(newCommands);
+ project.setDescription(desc1, new NullProgressMonitor());
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TimeStampBuilder.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TimeStampBuilder.java
new file mode 100644
index 0000000000..48fb76554f
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TimeStampBuilder.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mickael Istria (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.builder;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+
+public class TimeStampBuilder extends IncrementalProjectBuilder {
+
+ public static final String ID = TimeStampBuilder.class.getName();
+ public static final String PAUSE_DURATION = "pauseDuration";
+ private static final Map<IProject, Long> starts = Collections.synchronizedMap(new HashMap<>());
+ private static final Map<IProject, Long> ends = Collections.synchronizedMap(new HashMap<>());
+
+ @Override
+ protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
+ starts.put(getProject(), Long.valueOf(System.currentTimeMillis()));
+ try {
+ int pauseDuration = 1000;
+ if (args.containsKey(PAUSE_DURATION)) {
+ pauseDuration = Integer.parseInt(args.get(PAUSE_DURATION));
+ }
+ Thread.sleep(pauseDuration);
+ ends.put(getProject(), Long.valueOf(System.currentTimeMillis()));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return new IProject[0];
+ }
+
+ @Override
+ public ISchedulingRule getRule(int kind, Map<String, String> args) {
+ return null;
+ }
+
+ public static long end(IProject project) throws CoreException {
+ return ends.get(project).longValue();
+ }
+
+ public static long start(IProject project) throws CoreException {
+ return starts.get(project).longValue();
+ }
+
+ public static void clear() {
+ starts.clear();
+ ends.clear();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index c4127512a0..27ff0f3dd0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -156,6 +156,7 @@ import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
@@ -4498,7 +4499,11 @@ public final class JavaCore extends Plugin {
};
mainMonitor.subTask(Messages.javamodel_building_after_upgrade);
try {
- ResourcesPlugin.getWorkspace().run(runnable, mainMonitor.split(1));
+ ResourcesPlugin.getWorkspace().run(
+ runnable,
+ new MultiRule(Arrays.stream(projects).map(IJavaProject::getResource).toArray(ISchedulingRule[]::new)),
+ IWorkspace.AVOID_UPDATE,
+ mainMonitor.split(1));
} catch (CoreException e) {
// could not touch all projects
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
index 0aa71bebef..29f746a9ff 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
@@ -34,6 +34,7 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.SourceElementParser;
@@ -901,7 +902,7 @@ public class DeltaProcessor {
}
};
try {
- ResourcesPlugin.getWorkspace().run(runnable, monitor);
+ ResourcesPlugin.getWorkspace().run(runnable, new MultiRule(projectsToTouch), IWorkspace.AVOID_UPDATE, monitor);
} catch (CoreException e) {
throw new JavaModelException(e);
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
index 29453e2945..d272502db1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
@@ -16,7 +16,8 @@ package org.eclipse.jdt.internal.core.builder;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
-
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
@@ -30,6 +31,7 @@ import java.util.*;
@SuppressWarnings({"rawtypes", "unchecked"})
public class JavaBuilder extends IncrementalProjectBuilder {
+public static final String PREF_NULL_SCHEDULING_RULE = "useNullSchedulingRule"; //$NON-NLS-1$
IProject currentProject;
JavaProject javaProject;
IWorkspaceRoot workspaceRoot;
@@ -801,4 +803,12 @@ public String toString() {
? "JavaBuilder for unknown project" //$NON-NLS-1$
: "JavaBuilder for " + this.currentProject.getName(); //$NON-NLS-1$
}
+
+ @Override
+ public ISchedulingRule getRule(int kind, Map<String, String> args) {
+ if (InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID).getBoolean(PREF_NULL_SCHEDULING_RULE, false)) {
+ return null;
+ }
+ return super.getRule(kind, args);
+ }
}

Back to the top