Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 193687 Details for
Bug 343256
Workspace#buildInternal uses workspace root rule -> Saving while building is broken
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
fix 2 + tests
bug_343256.patch (text/plain), 20.57 KB, created by
James Blackburn
on 2011-04-20 08:30:30 EDT
(
hide
)
Description:
fix 2 + tests
Filename:
MIME Type:
Creator:
James Blackburn
Created:
2011-04-20 08:30:30 EDT
Size:
20.57 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.core.resources >Index: src/org/eclipse/core/internal/events/BuildManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/events/BuildManager.java,v >retrieving revision 1.125 >diff -u -r1.125 BuildManager.java >--- src/org/eclipse/core/internal/events/BuildManager.java 1 Feb 2011 11:37:52 -0000 1.125 >+++ src/org/eclipse/core/internal/events/BuildManager.java 20 Apr 2011 12:22:09 -0000 >@@ -14,11 +14,6 @@ > *******************************************************************************/ > package org.eclipse.core.internal.events; > >-import org.eclipse.core.resources.IProject; >-import org.eclipse.core.runtime.jobs.ISchedulingRule; >- >-import org.eclipse.core.resources.IBuildConfiguration; >- > import java.util.*; > import org.eclipse.core.internal.dtree.DeltaDataTree; > import org.eclipse.core.internal.resources.*; >@@ -169,6 +164,7 @@ > // For incremental builds, grab a pointer to the current state before computing the delta > currentTree = ((trigger == IncrementalProjectBuilder.FULL_BUILD) || clean) ? null : workspace.getElementTree(); > int depth = -1; >+ ISchedulingRule rule = null; > try { > //short-circuit if none of the projects this builder cares about have changed. > if (!needsBuild(currentBuilder, trigger)) { >@@ -177,6 +173,7 @@ > monitor.done(); > return; > } >+ rule = builder.getRule(trigger, args); > String name = currentBuilder.getLabel(); > String message; > if (name != null) >@@ -185,13 +182,27 @@ > message = NLS.bind(Messages.events_invoking_1, builder.getProject().getFullPath()); > monitor.subTask(message); > hookStartBuild(builder, trigger); >+ // Make the current tree immutable before releasing the WS lock >+ if (rule != null && currentTree != null) >+ currentTree.immutable(); > //release workspace lock while calling builders > depth = getWorkManager().beginUnprotected(); >+ // Acquire the rule required for running this builder >+ if (rule != null) { >+ Job.getJobManager().beginRule(rule, monitor); >+ // Now that we've acquired the rule, changes may have been made concurrently, ensure we're pointing at the >+ // correct currentTree so delta contains concurrent changes made in areas guarded by the scheduling rule >+ if (currentTree != null) >+ currentTree = workspace.getElementTree(); >+ } > //do the build > SafeRunner.run(getSafeRunnable(trigger, args, status, monitor)); > } finally { >+ // Re-acquire the WS lock, then release the scheduling rule > if (depth >= 0) > getWorkManager().endUnprotected(depth); >+ if (rule != null) >+ Job.getJobManager().endRule(rule); > // Be sure to clean up after ourselves. > if (clean || currentBuilder.wasForgetStateRequested()) { > currentBuilder.setLastBuiltTree(null); >@@ -1081,57 +1092,4 @@ > } > return project.isNatureEnabled(nature); > } >- >- /** >- * Returns the scheduling rule that is required for building the project. >- */ >- public ISchedulingRule getRule(IBuildConfiguration buildConfiguration, int trigger, String builderName, Map<String, String> args) { >- IProject project = buildConfiguration.getProject(); >- MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR, Messages.events_errors, null); >- if (builderName == null) { >- final ICommand[] commands; >- if (project.isAccessible()) { >- Set<ISchedulingRule> rules = new HashSet<ISchedulingRule>(); >- commands = ((Project) project).internalGetDescription().getBuildSpec(false); >- boolean hasNullBuildRule = false; >- BuildContext context = new BuildContext(buildConfiguration); >- for (int i = 0; i < commands.length; i++) { >- BuildCommand command = (BuildCommand) commands[i]; >- try { >- IncrementalProjectBuilder builder = getBuilder(buildConfiguration, command, i, status, context); >- if (builder != null) { >- ISchedulingRule builderRule = builder.getRule(trigger, args); >- if (builderRule != null) >- rules.add(builderRule); >- else >- hasNullBuildRule = true; >- } >- } catch (CoreException e) { >- status.add(e.getStatus()); >- } >- } >- if (rules.isEmpty()) >- return null; >- // Bug 306824 - Builders returning a null rule can't work safely if other builders require a non-null rule >- // Be pessimistic and fall back to the default build rule (workspace root) in this case. >- if (!hasNullBuildRule) >- return new MultiRule(rules.toArray(new ISchedulingRule[rules.size()])); >- } >- } else { >- // Returns the derived resources for the specified builderName >- ICommand command = getCommand(project, builderName, args); >- try { >- IncrementalProjectBuilder builder = getBuilder(buildConfiguration, command, -1, status); >- if (builder != null) >- return builder.getRule(trigger, args); >- >- } catch (CoreException e) { >- status.add(e.getStatus()); >- } >- } >- // Log any errors >- if (!status.isOK()) >- Policy.log(status); >- return workspace.getRoot(); >- } > } >Index: src/org/eclipse/core/internal/resources/Project.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java,v >retrieving revision 1.182 >diff -u -r1.182 Project.java >--- src/org/eclipse/core/internal/resources/Project.java 24 Feb 2011 12:12:30 -0000 1.182 >+++ src/org/eclipse/core/internal/resources/Project.java 20 Apr 2011 12:22:09 -0000 >@@ -25,6 +25,7 @@ > import org.eclipse.core.runtime.*; > import org.eclipse.core.runtime.content.IContentTypeMatcher; > import org.eclipse.core.runtime.jobs.ISchedulingRule; >+import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.osgi.util.NLS; > > public class Project extends Container implements IProject { >@@ -594,64 +595,39 @@ > * Implements all build methods on IProject. > */ > protected void internalBuild(final IBuildConfiguration config, final int trigger, final String builderName, final Map<String, String> args, IProgressMonitor monitor) throws CoreException { >- workspace.run(new IWorkspaceRunnable() { >- public void run(IProgressMonitor innerMonitor) throws CoreException { >- innerMonitor = Policy.monitorFor(innerMonitor); >- final ISchedulingRule rule = workspace.getRoot(); >- try { >- innerMonitor.beginTask("", Policy.totalWork); //$NON-NLS-1$ >- try { >- workspace.prepareOperation(rule, innerMonitor); >- if (!shouldBuild()) >- return; >- workspace.beginOperation(true); >- workspace.aboutToBuild(Project.this, trigger); >- } finally { >- workspace.endOperation(rule, false, innerMonitor); >- } >- final ISchedulingRule buildRule = workspace.getBuildManager().getRule(config, trigger, builderName, args); >- try { >- IStatus result; >- workspace.prepareOperation(buildRule, innerMonitor); >- //don't open the tree eagerly because it will be wasted if no build occurs >- workspace.beginOperation(false); >- result = workspace.getBuildManager().build(config, trigger, builderName, args, Policy.subMonitorFor(innerMonitor, Policy.opWork)); >- if (!result.isOK()) >- throw new ResourceException(result); >- } finally { >- workspace.endOperation(buildRule, false, innerMonitor); >- try { >- workspace.prepareOperation(rule, innerMonitor); >- //don't open the tree eagerly because it will be wasted if no change occurs >- workspace.beginOperation(false); >- workspace.broadcastBuildEvent(Project.this, IResourceChangeEvent.POST_BUILD, trigger); >- //building may close the tree, so open it >- if (workspace.getElementTree().isImmutable()) >- workspace.newWorkingTree(); >- } finally { >- workspace.endOperation(rule, false, Policy.subMonitorFor(innerMonitor, Policy.endOpWork)); >- } >- } >- } finally { >- innerMonitor.done(); >- } >- } >- /** >- * Returns whether this project should be built for a given trigger. >- * @return <code>true</code> if the build should proceed, and <code>false</code> otherwise. >- */ >- private boolean shouldBuild() { >+ monitor = Policy.monitorFor(monitor); >+ // Ensure that, if this job is being run with a rule, the rule contains the buildRule >+ final ISchedulingRule rule = Job.getJobManager().currentRule() != null ? workspace.getRuleFactory().buildRule() : null; >+ try { >+ monitor.beginTask("", Policy.totalWork); //$NON-NLS-1$ >+ try { >+ workspace.prepareOperation(rule, monitor); > ResourceInfo info = getResourceInfo(false, false); > int flags = getFlags(info); > if (!exists(flags, true) || !isOpen(flags)) >- return false; >- return true; >+ return; >+ workspace.beginOperation(true); >+ workspace.aboutToBuild(this, trigger); >+ IStatus result; >+ try { >+ result = workspace.getBuildManager().build(config, trigger, builderName, args, Policy.subMonitorFor(monitor, Policy.opWork)); >+ } finally { >+ //must fire POST_BUILD if PRE_BUILD has occurred >+ workspace.broadcastBuildEvent(this, IResourceChangeEvent.POST_BUILD, trigger); >+ } >+ if (!result.isOK()) >+ throw new ResourceException(result); >+ } finally { >+ //building may close the tree, but we are still inside an operation so open it >+ if (workspace.getElementTree().isImmutable()) >+ workspace.newWorkingTree(); >+ workspace.endOperation(rule, false, Policy.subMonitorFor(monitor, Policy.endOpWork)); > } >- >- }, null, IWorkspace.AVOID_UPDATE, monitor); >+ } finally { >+ monitor.done(); >+ } > } > >- > /** > * Closes the project. This is called during restore when there is a failure > * to read the project description. Since it is called during workspace restore, >Index: src/org/eclipse/core/internal/resources/Workspace.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java,v >retrieving revision 1.244 >diff -u -r1.244 Workspace.java >--- src/org/eclipse/core/internal/resources/Workspace.java 1 Feb 2011 11:37:52 -0000 1.244 >+++ src/org/eclipse/core/internal/resources/Workspace.java 20 Apr 2011 12:22:09 -0000 >@@ -163,7 +163,7 @@ > * reads and concurrent writes, write access to the tree is governed > * by {@link WorkManager}. > */ >- protected ElementTree tree; >+ protected volatile ElementTree tree; > > /** > * This field is used to control access to the workspace tree during >@@ -440,7 +440,9 @@ > */ > private void buildInternal(IBuildConfiguration[] configs, int trigger, boolean buildReferences, IProgressMonitor monitor) throws CoreException { > monitor = Policy.monitorFor(monitor); >- final ISchedulingRule rule = getRuleFactory().buildRule(); >+ // PRE + POST_BUILD, and the build itself are allowed to modify resources, so require the current thread's scheduling rule >+ // to either contain the WR or be null. Therefore, if not null, ensure it contains the WR rule... >+ final ISchedulingRule rule = Job.getJobManager().currentRule() == null ? null : getRuleFactory().buildRule(); > try { > monitor.beginTask("", Policy.opWork); //$NON-NLS-1$ > try { >#P org.eclipse.core.tests.resources >Index: src/org/eclipse/core/tests/internal/builders/RelaxedSchedRuleBuilderTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/RelaxedSchedRuleBuilderTest.java,v >retrieving revision 1.2 >diff -u -r1.2 RelaxedSchedRuleBuilderTest.java >--- src/org/eclipse/core/tests/internal/builders/RelaxedSchedRuleBuilderTest.java 1 Feb 2011 11:37:48 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/builders/RelaxedSchedRuleBuilderTest.java 20 Apr 2011 12:22:10 -0000 >@@ -10,6 +10,7 @@ > *******************************************************************************/ > package org.eclipse.core.tests.internal.builders; > >+import java.io.ByteArrayInputStream; > import java.util.Map; > import junit.framework.Test; > import junit.framework.TestSuite; >@@ -121,10 +122,11 @@ > > /** > * Test two builders, each with relaxed scheduling rules, run in the same build operation >- * Each should be run with their own scheduling rule. >+ * Each should be run with precisely their requested scheduling rule. > * Tests: > * Bug 306824 - null scheduling rule and non-null scheduling rule don't work together > * Builders should have separate scheduling rules >+ * Bug 343256 - relaxed scheduling rules when using IWorkspace.build methods > * @throws Exception > */ > public void testTwoBuildersRunInOneBuild() throws Exception { >@@ -156,7 +158,7 @@ > > public IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { > // shared scheduling rule >- assertTrue(Job.getJobManager().currentRule().contains(project)); >+ assertTrue(Job.getJobManager().currentRule().equals(project)); > tb1.setStatus(TestBarrier.STATUS_RUNNING); > tb1.waitForStatus(TestBarrier.STATUS_WAIT_FOR_DONE); > tb1.setStatus(TestBarrier.STATUS_DONE); >@@ -173,7 +175,7 @@ > > public IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { > // shared scheduling rule >- assertTrue(Job.getJobManager().currentRule() == null || Job.getJobManager().currentRule().contains(getWorkspace().getRoot())); >+ assertTrue(Job.getJobManager().currentRule() == null); > tb2.setStatus(TestBarrier.STATUS_RUNNING); > tb2.waitForStatus(TestBarrier.STATUS_WAIT_FOR_DONE); > tb2.setStatus(TestBarrier.STATUS_DONE); >@@ -181,8 +183,11 @@ > } > }); > >- // Run the build >- Job j = new Job("build job1") { >+ // Run the builds >+ >+ // Test IProject.build() >+ >+ Job j = new Job("IProject.build()") { > protected IStatus run(IProgressMonitor monitor) { > try { > project.build(IncrementalProjectBuilder.FULL_BUILD, monitor); >@@ -195,7 +200,28 @@ > j.schedule(); > > // Wait for the build to transition >+ tb1.waitForStatus(TestBarrier.STATUS_RUNNING); >+ tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ tb1.waitForStatus(TestBarrier.STATUS_DONE); > >+ tb2.waitForStatus(TestBarrier.STATUS_RUNNING); >+ tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ tb2.waitForStatus(TestBarrier.STATUS_DONE); >+ >+ // Now test IWorkspace.build() >+ >+ j = new Job("IWorkspace.build()") { >+ protected IStatus run(IProgressMonitor monitor) { >+ try { >+ getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, monitor); >+ } catch (CoreException e) { >+ fail(); >+ } >+ return Status.OK_STATUS; >+ } >+ }; >+ j.schedule(); >+ // Wait for the build to transition > tb1.waitForStatus(TestBarrier.STATUS_RUNNING); > tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); > tb1.waitForStatus(TestBarrier.STATUS_DONE); >@@ -203,6 +229,122 @@ > tb2.waitForStatus(TestBarrier.STATUS_RUNNING); > tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); > tb2.waitForStatus(TestBarrier.STATUS_DONE); >+ >+ // Now test IWorkspace.build(IBuildConfiguration[], ...) >+ >+ j = new Job("IWorkspace.build(IBuildConfiguration[], ...)") { >+ protected IStatus run(IProgressMonitor monitor) { >+ try { >+ getWorkspace().build(new IBuildConfiguration[] {project.getActiveBuildConfig()}, IncrementalProjectBuilder.FULL_BUILD, true, monitor); >+ } catch (CoreException e) { >+ fail(); >+ } >+ return Status.OK_STATUS; >+ } >+ }; >+ j.schedule(); >+ // Wait for the build to transition >+ tb1.waitForStatus(TestBarrier.STATUS_RUNNING); >+ tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ tb1.waitForStatus(TestBarrier.STATUS_DONE); >+ >+ tb2.waitForStatus(TestBarrier.STATUS_RUNNING); >+ tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ tb2.waitForStatus(TestBarrier.STATUS_DONE); >+ >+ // Bug 331187 >+ // // Auto-build >+ // getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, getMonitor()); >+ // setAutoBuilding(true); >+ // // Wait for the build to transition >+ // tb1.waitForStatus(TestBarrier.STATUS_RUNNING); >+ // tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ // tb1.waitForStatus(TestBarrier.STATUS_DONE); >+ // >+ // tb2.waitForStatus(TestBarrier.STATUS_RUNNING); >+ // tb2.setStatus(TestBarrier.STATUS_WAIT_FOR_DONE); >+ // tb2.waitForStatus(TestBarrier.STATUS_DONE); >+ } >+ >+ /** >+ * As the builder is run with a relaxed scheduling rule, we ensure that any changes made before >+ * the build is actually run are present in the delta. >+ * Acquiring the scheduling rule must be done outside of the WS lock, so this tests that >+ * a change which sneaks in during the window or the build thread acquiring its scheduling >+ * rule, is correctly present in the builder's delta. >+ * @throws Exception >+ */ >+ public void testBuilderDeltaUsingRelaxedRuleBug343256() throws Exception { >+ String name = "testBuildDeltaUsingRelaxedRuleBug343256"; >+ setAutoBuilding(false); >+ final IProject project = getWorkspace().getRoot().getProject(name); >+ final IFile foo = project.getFile("foo"); >+ create(project, false); >+ >+ IProjectDescription desc = project.getDescription(); >+ desc.setBuildSpec(new ICommand[] {createCommand(desc, EmptyDeltaBuilder.BUILDER_NAME, "Project1Build1")}); >+ project.setDescription(desc, getMonitor()); >+ >+ // Ensure the builder is instantiated >+ project.build(IncrementalProjectBuilder.FULL_BUILD, getMonitor()); >+ >+ final TestBarrier tb1 = new TestBarrier(TestBarrier.STATUS_WAIT_FOR_START); >+ >+ // Create a builder set a null scheduling rule >+ EmptyDeltaBuilder builder = EmptyDeltaBuilder.getInstance(); >+ >+ // Set the rule call-back >+ builder.setRuleCallback(new BuilderRuleCallback() { >+ public ISchedulingRule getRule(String name, IncrementalProjectBuilder builder, int trigger, Map args) { >+ tb1.setStatus(TestBarrier.STATUS_START); >+ tb1.waitForStatus(TestBarrier.STATUS_WAIT_FOR_RUN); >+ try { >+ // Give the resource modification time be queued >+ Thread.sleep(10); >+ } catch (InterruptedException e) { >+ fail(); >+ } >+ return project; >+ } >+ >+ public IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { >+ // shared scheduling rule >+ assertTrue(Job.getJobManager().currentRule().equals(project)); >+ // assert that the delta contains the file foo >+ IResourceDelta delta = getDelta(project); >+ assertNotNull("1.1", delta); >+ assertTrue("1.2", delta.getAffectedChildren().length == 1); >+ assertTrue("1.3", delta.getAffectedChildren()[0].getResource().equals(foo)); >+ tb1.setStatus(TestBarrier.STATUS_DONE); >+ return super.build(kind, args, monitor); >+ } >+ }); >+ >+ // Run the incremental build >+ Job j = new Job("IProject.build()") { >+ protected IStatus run(IProgressMonitor monitor) { >+ try { >+ project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); >+ } catch (CoreException e) { >+ fail(); >+ } >+ return Status.OK_STATUS; >+ } >+ }; >+ j.schedule(); >+ >+ // Wait for the build to transition to getRule >+ tb1.waitForStatus(TestBarrier.STATUS_START); >+ // Modify a file in the project >+ j = new Job("IProject.build()") { >+ protected IStatus run(IProgressMonitor monitor) { >+ tb1.setStatus(TestBarrier.STATUS_WAIT_FOR_RUN); >+ ensureExistsInWorkspace(foo, new ByteArrayInputStream(new byte[0])); >+ return Status.OK_STATUS; >+ } >+ }; >+ j.schedule(); >+ tb1.waitForStatus(TestBarrier.STATUS_DONE); > } > > } >Index: src/org/eclipse/core/tests/internal/builders/TestBuilder.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/builders/TestBuilder.java,v >retrieving revision 1.18 >diff -u -r1.18 TestBuilder.java >--- src/org/eclipse/core/tests/internal/builders/TestBuilder.java 1 Feb 2011 11:37:48 -0000 1.18 >+++ src/org/eclipse/core/tests/internal/builders/TestBuilder.java 20 Apr 2011 12:22:10 -0000 >@@ -26,6 +26,8 @@ > * A test specific call-back which can be ticked on #getRule(...) & #build(...) > */ > public static class BuilderRuleCallback { >+ private IncrementalProjectBuilder builder; >+ > public BuilderRuleCallback() { > } > >@@ -42,6 +44,10 @@ > public IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { > return new IProject[0]; > } >+ >+ public IResourceDelta getDelta(IProject project) { >+ return builder.getDelta(project); >+ } > } > > /** >@@ -101,6 +107,7 @@ > logPluginLifecycleEvent(getBuildId()); > if (ruleCallBack == null) > return new IProject[0]; >+ ruleCallBack.builder = this; > return ruleCallBack.build(kind, args, monitor); > } > >@@ -111,6 +118,7 @@ > public ISchedulingRule getRule(int trigger, Map<String, String> args) { > if (ruleCallBack == null) > return super.getRule(trigger, args); >+ ruleCallBack.builder = this; > return ruleCallBack.getRule(name, this, trigger, args); > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 343256
:
193567
|
193622
|
193687
|
193763
|
193795
|
193849
|
193919
|
194499
|
194597