Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 341360 - Thread-safety issue in WorkManager
Summary: Thread-safety issue in WorkManager
Status: RESOLVED DUPLICATE of bug 249951
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Resources (show other bugs)
Version: 3.7   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-Resources-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-03-30 09:55 EDT by Vladimir Piskarev CLA
Modified: 2011-03-31 14:12 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vladimir Piskarev CLA 2011-03-30 09:55:46 EDT
Build Identifier: 

WorkManager#getPreparedOperationDepth() may return incorrect answer due to race-condition. This, in turn, may lead to timing problems with resource change notifications.

Reproducible: Always

Steps to Reproduce:
Consider two workspace runnables: one with "IWorkspaceRoot" scheduling rule, the other with "null" scheduling rule. Suppose they are run as top-level operations in two different threads concurrently. Let's imagine the following chain of events. The operation with "IWorkspaceRoot" scheduling rule begins to run and gets preempted just before the call "getWorkManager().endUnprotected()" in Workspace#run. Then the second operation begins to run and in turn gets preempted just after the line "getWorkManager().beginUnprotected()". The first operation resumes execution, calls "getWorkManager().endUnprotected()" and enters "endOperation()" method. Notice that when "depthOne" is computed, "workManager.getPreparedOperationDepth()" will return 2 (not 1) and therefore the operation will not be regarded as "top-level". Because of this, instead of  synchronously notifying resource change listeners, an asynchronous "notify job" will be scheduled. This may lead to "interim inconsistency" in models such as the Java Model which are updated by delta processors.

The issue described was encountered in "real life" when the following assertion failed: 

    IWorkspaceRunnable runnable = new IWorkspaceRunnable()
    {
        public void run(IProgressMonitor monitor) throws CoreException
        {
            // checkout Java project (uses Resources API)
        }
    };
    getWorkspace().run(runnable, null); // in empty workspace
    IJavaElement[] javaProjects = javaModel.getChildren();
    assertTrue(javaProjects.length > 0);

because JDT's JREUpdateJob was interfering from another thread.
Comment 1 James Blackburn CLA 2011-03-30 10:05:57 EDT
See also bug 306214, bug 249951 & bug 273676.

In general you can make no assumption about when the resource change delta will fire.  It may fire in the current resource changing thread or in another notification thread periodically.  The WS guarantees that listeners will eventually be notified of changes, but not when.

*** This bug has been marked as a duplicate of bug 249951 ***
Comment 2 Vladimir Piskarev CLA 2011-03-31 02:12:03 EDT
Just wanted to be more precise that the notification problem described is just a consequence. The major issue is a kind of race condition on "preparedOperations" field in WorkManager.

Also, I forgot to mention explicitly that the problem has nothing to do with the periodic notifications mechanism. But it has everything to do with the mechanism responsible for determining if the given workspace operation is a "top-level" operation.

The sequence of events described illustrates that under certain conditions workspace operations from different threads may simultaneously update the "preparedOperations" field. As far as I can see this counter is not supposed to be "shared" among multiple threads. (In particular, the JavaDoc on WorkManager says "This class also tracks operation state for <i>each thread</i> that is involved in an operation. This includes prepared and running operation depth, auto-build strategy and cancel state." - emphasis is mine)

The direct consequence is that an operation which is "top-level" may under certain conditions not be regarded as such by "finalization" machinery in Workspace#endOperation(). I believe this is a major concern that deserves bumping importance level and thorough consideration.

Hoping for a word from John Arthorne.
Comment 3 James Blackburn CLA 2011-03-31 03:24:47 EDT
(In reply to comment #2)
> Just wanted to be more precise that the notification problem described is just
> a consequence. The major issue is a kind of race condition on
> "preparedOperations" field in WorkManager.

Where is the race?  AFAICS (open call-hierarchy on preparedOperations) the field is only ever accessed while WorkManager#lock is held, is there something I'm missing?

> Also, I forgot to mention explicitly that the problem has nothing to do with
> the periodic notifications mechanism. But it has everything to do with the
> mechanism responsible for determining if the given workspace operation is a
> "top-level" operation.

Right, this is precisely the issue described in bug 273676 isn't it?

If it's just that the event isn't always fired at the end of your top-level operation then, but is fired at some point in the future, then this is expected:
see bug 273676 comment 2.

> The sequence of events described illustrates that under certain conditions
> workspace operations from different threads may simultaneously update the
> "preparedOperations" field. As far as I can see this counter is not supposed to
> be "shared" among multiple threads. (In particular, the JavaDoc on WorkManager
> says "This class also tracks operation state for <i>each thread</i> that is
> involved in an operation. This includes prepared and running operation depth,
> auto-build strategy and cancel state." - emphasis is mine)

Ok, the JavaDoc should likely be updated.  Does the discussion in bug 273676 help? In particular bug 273676 comment 3: the preparedOperations count keeps count of all operations currently checked into the workspace (irrespective of thread).  When this decrements to 0, or enough time has elapsed, the workspace performs a notification.

Even WorkspaceJobs with null scheduling rules are 'checked-in' to the workspace and contribute to the number of prepared operations.
Comment 4 Vladimir Piskarev CLA 2011-03-31 07:24:49 EDT
Thank you very much, James! You were very helpful indeed. I really missed bug 273676, my apologies. But if (as John said) this is intentional and desired behavior, how should the code like I described be structured? Something like the following:

    IWorkspaceRunnable runnable = new IWorkspaceRunnable()
    {
        public void run(IProgressMonitor monitor) throws CoreException
        {
            // checkout Java project (uses Resources API)
        }
    };
    getWorkspace().run(runnable, null); // in empty workspace
    IJavaElement[] javaProjects = null;
    for (int i = 0; i < N; i++) // what is a good N?
    {
        javaProjects = javaModel.getChildren();
        if (javaProjects.length > 0)
            break;
        Thread.sleep(100);
    }
    if (javaProject.length == 0)
        fail();
    // do something with the created Java project (using JDT API)

or is there a better "work-around"?
Comment 5 James Blackburn CLA 2011-03-31 07:33:37 EDT
Presumably you need to register a listener with the JavaModel to tell you when any of its elements have changed. See also:
http://help.eclipse.org/helios/nftopic/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#ADDED
http://dev.eclipse.org/newslists/news.eclipse.tools/msg53342.html
Comment 6 Vladimir Piskarev CLA 2011-03-31 07:58:23 EDT
Well, it gets more complicated than I thought it would be. The control flow which I believed to be purely synchronous becomes an asynchronous one.

Thank you for your replies James! I learned quite a bit from this "bug".
Comment 7 John Arthorne CLA 2011-03-31 10:48:42 EDT
Thanks for explaining this James.

Vladimir, you could use IWorkspace#checkpoint(false) to ensure the java model is reconciled after your checkout.
Comment 8 Vladimir Piskarev CLA 2011-03-31 14:12:50 EDT
John, I really can't express how I'm grateful for your invaluable (as always) help! I did not know about this facility! Thank you!!!