Bug 89301 - Any user operation that would trigger an autobuild should cancel a running autobuild
Summary: Any user operation that would trigger an autobuild should cancel a running au...
Status: VERIFIED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 enhancement with 2 votes (vote)
Target Milestone: 3.4 M2   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 202442 (view as bug list)
Depends on: 206637 203058
Blocks:
  Show dependency tree
 
Reported: 2005-03-28 17:45 EST by Stefan Xenos CLA
Modified: 2012-09-21 15:06 EDT (History)
15 users (show)

See Also:


Attachments
Proposed patch (4.42 KB, patch)
2007-09-07 15:36 EDT, Kent Johnson CLA
no flags Details | Diff
Shows a "User is waiting" dialog, waiting for a job that won't terminate and forbids to save the document. (35.60 KB, image/png)
2011-02-23 11:08 EST, Michael Meß CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Xenos CLA 2005-03-28 17:45:30 EST
1. Turn on autobuild
2. Take a moderately-sided workspace (something that will take at least 30 sec
to compile)
3. "Clean..." the workspace
4. While the build is running, save a file.

You will get a "User Operation is Waiting" dialog until the build finishes. 

The user can safely cancel the "Building Workspace" job and proceed with their
work since saving the file will trigger another autobuild which will end up
taking into account the saved file plus everything that the cancelled build
would have done.

It should not be necessary for users to figure this out, see the dialog, or to
manually cancel the build. 

Basically, any job that was triggered as the result of an autobuild should be
flagged. If another job arrives that needs write access to the workspace any
running autobuild jobs should be cancelled and restarted once the new job finishes. 

This is most noticiable when the UI is waiting for NEWJOB, but it also applies
when both jobs are background jobs. For example, imagine that the user requests
a "clean..." on all projects and a few moments later starts a background job
that will end up replacing the entire contents of the workspace. There would be
no point continuing with the autobuild triggered by the "clean..." since its
output will be rendered redundant once the replace job runs.
Comment 1 Stefan Xenos CLA 2005-03-28 17:45:56 EST
Not sure exactly who to file this against, since it clearly spans components.
Comment 2 John Arthorne CLA 2005-03-28 18:13:39 EST
Autobuild can currently be either "interrupted", or "cancelled".  A build is
interrupted automatically when, as you mention, another thread is waiting to
modify the workspace while the build is running.  Individual builders, such as
the Java builder, do not currently respond to builder interruption.  The
platform core build infrastructure checks for an interrupt after each individual
builder has finished running.  The result is that interrupting a build is not
nearly as responsive as cancelling a build.

The reason for having this distinction is that cancellation typically results in
builder work being lost.  Essentially, cancellation of an incremental build and
gracefully recovering on the next build is too complicated - the Java builder
simply throws away all its build state on cancellation, and the next build will
be a full build.  This is typically not a good thing from the user's point of
view, and results in the subsequent build being very expensive. This is why we
don't cancel builds "for free" when another thread is waiting.  In your
particular case, since you're doing a full build anyway, there is no harm in
cancelling the builder.

The short summary is that the builder infrastructure is tuned for the
incremental build case - the clean and full rebuild of your workspace is
generally never required.  We sometimes use it because of various bugs in the
integration builds, but essentially clean and full build only used as a
workaround for other bugs.  I am curious to know if you hit these long pauses
waiting for the builder in incremental build cases?

If we decided this case was worth optimizing, the Java builder could be changed
to respond to interruption more quickly during a full build (since there is no
incremental build state to lose), by checking the flag
IncrementalProjectBuilder.isInterrupted().
Comment 3 Stefan Xenos CLA 2005-03-28 19:26:03 EST
I don't often do a funll rebuild. I just used that as an example since it's easy
to reproduce. I seem to hit this frequently even with incremental builds.

My workspace isn't in a good enough state to try testing right now, but I seem
to recall observing it in the following situations:

1. Perform several project-wide operations at once. For example, replace the
first project from head, delete the second project, and update the third project
from CVS. Each operation triggers a build and waits on the previous one.

2. I save a java file during an autobuild (or CVS replace... or update from
CVS... etc. etc.)

3. I have a bunch of dirty editors. I save them one-at-a-time, the first one
triggers an autobuild, and I end up waiting before being able to save the rest.

4. I have an editor open. I save it, triggering an autobuild. Then I notice a
typo in what I just saved, correct the typo, re-save, and end up with the UI
thread waiting on the builder.
Comment 4 Olivier Thomann CLA 2006-10-06 12:40:23 EDT
In 3.3 build, when such operation is triggered, you get the choice of cancelling the running build.
Closing as WORKSFORME.
Comment 5 Markus Keller CLA 2007-07-25 09:04:56 EDT
> Closing as WORKSFORME.

I disagree. Every time I switch to a new integration build, autobuild basically rebuilds the whole workspace. During this time, my workbench is almost unusable, since most operations (like quick fixes or saving a file) raise a "User Operation is Waiting" dialog, where I have to find the build job and cancel it manually (often more than once).

This is also a problem when you select a big number of incoming changes in the Synchronize view, choose to Update them, and then try to update another incoming change.
Comment 6 Boris Bokowski CLA 2007-08-03 07:56:33 EDT
The problem is that it is not clear to the end user which jobs can be canceled without causing problems later on. Ideally, if the Java builder is blocking a UI operation, it should just go away automatically without even showing the dialog, because we know that the build will continue after the UI operation. The system should do this for the user rather than the user having to learn about jobs, how to cancel them, and how to tell which jobs are safe to cancel.
Comment 7 Jerome Lanneluc CLA 2007-08-09 04:58:35 EDT
I agree with John that only the full build case is worth optimizing from the Java builder standpoint. Interrupting an incremental build would force us to start a full build next time the Java builder is invoked.

John, if we checked IncrementalProjectBuilder.isInterrupted() during a full build, when would the Java builder get the next full build request ? I'm thinking of the autobuild case that usually guaranties that the workspace is entirely built. If we abort the full build while the user operation is running, do we get a full build request once the user operation has finished ?
Comment 8 Kevin McGuire CLA 2007-08-09 11:46:32 EDT
Further to Markus' and Boris' comments (5 and 6), the whole point to me of jobs is to ensure that the UI remains responsive to the user while long background operations like builds are happening.  That however is not the experience we are providing as outlined in this bug.

For products like WID the tendency is to revert to turning off autobuild and doing manual builds so that you (the user) can regain control over when you can actually use the UI (and when you should go get a coffee).  So our whole story is kind of failing in practice. Note the WID problem involves the JDT builder but many others as well.
Comment 9 Boris Bokowski CLA 2007-08-09 11:50:22 EDT
(In reply to comment #7)
>... Interrupting an incremental build would force us to
> start a full build next time the Java builder is invoked.

Just curious - why is this the case?  Does it force a full build for the entire workspace, or the particular project that was being built at the time it was interrupted?
Comment 10 John Arthorne CLA 2007-08-09 13:22:37 EDT
Jerome, regarding comment #7: the recommended pattern if you interrupt is to call IncrementalProjectBuilder.forgetLastBuiltState() before returning. This ensures that the next invocation of that builder on that project will be a full build (because this method causes us to throw away the pointer to the old tree state, so computing a delta is impossible).

Some general comments: 

Since this bug is a couple of years old, I should point out that there were some bugs in past releases that caused autobuild interruption to not work properly. The most recent was bug 170356 in 3.2.2 and early 3.3 milestones. For what it's worth, the interruption behaviour now is much better than it was in the past.

For the Java builder case, I think optimizing only the full build case is a reasonable thing to try.  Incremental Java builds are rarely very long - it's likely that most cases where people notice a delay is due to a full build.

I also wanted to point out that build isn't the root cause of the problem here. Autobuild is always happening outside the UI thread. The root cause of the UI being blocked is people attempt to perform long-running work (obtain locks) in the UI thread.
Comment 11 Boris Bokowski CLA 2007-08-09 14:04:02 EDT
(In reply to comment #10)
> I also wanted to point out that build isn't the root cause of the problem here.
> Autobuild is always happening outside the UI thread. The root cause of the UI
> being blocked is people attempt to perform long-running work (obtain locks) in
> the UI thread.

A common scenario is when you try to save an editor while the build is running, the "operation is blocked" dialog is coming up. So yes, someone else is obtaining a lock in the UI thread, but for a good reason.  Overall, the user experience would be better if we had a way to automatically cancel and/or pause the build in this case, letting the user operation proceed, and then resuming the build.
Comment 12 John Arthorne CLA 2007-08-09 14:14:29 EDT
> Overall, the user experience would be better if we had a way to automatically 
> cancel and/or pause the build in this case, letting the user operation proceed, 
> and then resuming the build.

Yes, absolutely agreed, this would be better. However, incremental build is quite a complicated algorithm - it is very difficult to stop at a random point in the middle and resume exactly where it left off. There is a trade-off between responsiveness and efficiency here. It could cancel immediately, and then do a full build later. This could make a build that would take one second end up taking over a minute.
Comment 13 Jerome Lanneluc CLA 2007-08-13 06:29:03 EDT
(In reply to comment #10)
> Jerome, regarding comment #7: the recommended pattern if you interrupt is to
> call IncrementalProjectBuilder.forgetLastBuiltState() before returning. This
> ensures that the next invocation of that builder on that project will be a full
> build (because this method causes us to throw away the pointer to the old tree
> state, so computing a delta is impossible).

Thanks John. The question is however: when does the "next invocation of that builder" occurs ? In auto-build mode, we cannot expect the user to force a build to trigger the invocation of the builder. If this invocation doesn't occur automatically, then I don't think interrupting a full build is a good idea either.
Comment 14 John Arthorne CLA 2007-08-13 12:42:37 EDT
>In auto-build mode, we cannot expect the user to force a
> build to trigger the invocation of the builder. If this invocation doesn't
> occur automatically, then I don't think interrupting a full build is a good
> idea either.

I agree.  When the autobuild job auto-interrupts, it also auto-resumes ;)  You can assume when autobuild is on, the resources plugin will take responsibility for making sure everything's in a built state at the earliest opportunity.  The autobuild job reschedules itself immediately when interrupted. This puts it back in the job queue, and it will run as soon as the operation that interrupted it completes.
Comment 15 Jerome Lanneluc CLA 2007-08-14 07:09:14 EDT
Thanks John.

Kent, I think we should consider honoring IncrementalProjectBuilder.isInterrupted() during a full build by calling IncrementalProjectBuilder.forgetLastBuiltState().
Comment 16 Boris Bokowski CLA 2007-09-06 10:54:05 EDT
*** Bug 202442 has been marked as a duplicate of this bug. ***
Comment 17 Kent Johnson CLA 2007-09-07 15:36:19 EDT
Created attachment 77915 [details]
Proposed patch
Comment 18 Kent Johnson CLA 2007-09-07 15:38:28 EDT
Released patch into HEAD for 3.4M2

Verified by ensuring that only full builds are restarted when a small change is made to a source file AND that incremental builds are not restarted when the same change is made.
Comment 19 Kent Johnson CLA 2007-09-12 09:44:47 EDT
Caused problems for some users - removed for now.
Comment 20 Kent Johnson CLA 2007-09-12 13:54:11 EDT
Because of the problems found with some misbehaving plugins, we cannot rely on the interrupted flag.

Removed patch from HEAD

See bug 203058
Comment 21 Benno Baumgartner CLA 2007-09-13 04:38:14 EDT
(In reply to comment #20)
> Because of the problems found with some misbehaving plugins, we cannot rely on
> the interrupted flag.
> 
> Removed patch from HEAD
> 
> See bug 203058
> 

Mmm, I don't understand that: In AutoBuildJob.interrupt() it says: 'Another thread is attempting to modify the workspace. Flag the auto-build as interrupted...'

Can't the code in Workspace.prepareOperation:

if (rule != null)
	buildManager.interrupt();

be safely replaced by something like

if (rule != null && 
           ResourcesPlugin.getWorkspace().getRoot().isConflicting(rule))
	buildManager.interrupt();

The rule leading to Bug 203058 is called 'NonLockingRule' I therefore guess that it will not conflict with the workspace rule...
Comment 22 John Arthorne CLA 2007-09-13 10:15:19 EDT
Benno, you may be right that we can optimize the interrupt behaviour a bit. Can you enter a separate bug against Platform Resources for that? It's really separate from this bug about increasing responsiveness to interrupts.
Comment 23 Jerome Lanneluc CLA 2007-09-17 10:12:55 EDT
Verified for 3.4M2
Comment 24 Markus Keller CLA 2007-10-15 06:02:18 EDT
(In reply to comment #20)
> Because of the problems found with some misbehaving plugins, we cannot rely on
> the interrupted flag.

Sorry, but this cannot be the end of the story.

We have identified a scenario where we agree that builds are not interrupted as timely as they should, and we have a proper fix for it, but we don't release the fix, because it *could* cause problems with misbehaving third-party builders (it probably won't after bug 203410, see comment 21).

IMO, JDT/Core should re-release the fix now, since it is just using a non-deprecated API in the suggested way.

If the Platform/Resources team thinks that the platform should prevent the problem from bug 203058, then either IncrementalProjectBuilder.isInterrupted() should be publicly marked as broken/deprecated, or the builder should try to detect such endless loop scenarios where a builder is cancelling itself multiple times when interrupted.
Comment 25 Kent Johnson CLA 2007-10-16 13:31:13 EDT
Actually I'll disagree on several points:

1. "That the fix is good"

I used the fix for over a week and didn't like it.

We need a threshold that controls when a full build should be cancelled and then restarted with the new change included.

As a user I would rather wait 40 seconds for the full build (its already been running for 20 seconds) to finish then 0.5 seconds for the incremental build to run, then stop the full build & wait 1 minute for it run completely again.

2. "it *could* cause problems with misbehaving third-party builders"

'Could' is more than enough reason to not release the fix.

3. Until the platform has a solution for repeated offenders, then we do not have an acceptable solution to the problem.
Comment 26 Markus Keller CLA 2007-10-17 11:42:50 EDT
> We need a threshold that controls when a full build should be cancelled [..]

Sounds good to me.

> 3. Until the platform has a solution for repeated offenders, then we do not
> have an acceptable solution to the problem.

I disagree here. Eclipse is an open platform, and therefore, there's always room for misbehaving third-party plug-ins that can impede the functioning of the platform. I filed bug 206637 for better detection of this case in the platform.

However, I don't think the existence of one misbehaving plug-in should prevent JDT/Core from making progress by using an API the way it's intended to be used.
Comment 27 Kent Johnson CLA 2007-10-17 12:07:39 EDT
>I don't think the existence of one misbehaving plug-in should prevent JDT/Core

I do.

If a single user cannot build their workspace, then this fix is insufficient & cannot be released.

We need the platform to detect repeat offenders & ignore them during future builds.
Comment 28 Philipe Mulet CLA 2008-12-04 09:37:09 EST
Was there any progress on platform side ? If not, I think Kent is right that we cannot be right alone and break the world.
Comment 29 Markus Keller CLA 2008-12-04 12:31:57 EST
> Was there any progress on platform side ?

Yes, bug 203410 has been fixed (10 days after it had been filed), so we currently don't have a single scenario that would have a problem.
Comment 30 Kent Johnson CLA 2008-12-10 14:49:15 EST
I think we should wait to see the impact of bug 198591

There are better solutions to improve the 'feel' of editing a file during a build than killing the build & restarting it.

If builds do not need workspace locks or do not need them for very long then saving a file should succeed sooner & possibly soon enough when compared to the alternative of killing a build.
Comment 31 Michael Meß CLA 2011-02-23 11:08:02 EST
Created attachment 189612 [details]
Shows a "User is waiting" dialog, waiting for a job that won't terminate and forbids to save the document.
Comment 32 Michael Meß CLA 2011-02-23 11:18:50 EST
Version: Helios Release
Build id: 20100617-1415

The problem is still there and it is quite annoying when work gets lost because it cannot be saved.
There should be an option to force eclipse to save the document without taking care of running jobs.
If a file is saved, a running build could continue and the saved document can be marked "dirty" for compiling. After the build run finished, the saved document and any other which have dependencies could be recompiled in a second run.
The user should always be able to save or modify any files. If eclipse gets idle then it could start to recompile the modified files and depending others as if they were just saved in that time.
Comment 33 Dani Megert CLA 2011-02-23 12:33:40 EST
(In reply to comment #32)
> Version: Helios Release
> Build id: 20100617-1415
> 
> The problem is still there and it is quite annoying when work gets lost
> because it cannot be saved.

I agree, however, as you can see the offending builder is the Maven builder. I suggest you report your bug there.
Comment 34 J.R. Willett CLA 2012-09-21 15:06:21 EDT
I used to wait for the "User Operating is Waiting" dialog to go away on its own, but I recently realized that that in my version of eclipse (latest) I can just close the dialog and keep editing files.

This dialog is only modal until you close it. Closing it does not stop the queued actions from happening in the background while you continue working!