Community
Participate
Working Groups
Build Identifier: I20100608-0911 Setup description: ------------------ In my setup the Java text editor is being updated both by a user input (keyboard), and a plugin I’m developing. The plugin uses the standard Display.getDefault().syncExec method to execute its changes to the Java Model (e.g. createMethod, createField, etc.). The problem: ------------ Seems that under certain timing conditions, if the user and the plugin almost simultaneously add a new method to the Java Model, only one of new methods is reported to the IElementChangedListener (and is usually the one introduced by the plugin). This notification runs in the main thread and looks like : [Working copy] Temp.java[*]: {CHILDREN | FINE GRAINED} Temp[*]: {CHILDREN | FINE GRAINED} foo()[+]: {} Where foo is the method that the plugin introduced. I’d expect the second method to be reported much the same way. Sometimes it does, but under certain timing conditions, it does not, and the second method goes off the radar. The notification I get about it looks like so and does not provide the details I expect to be getting: [Working copy] Temp.java[*]: {AST AFFECTED} (This notification runs in the org.eclipse.jdt.internal.ui.text.JavaReconciler thread). To sum things up, two methods are added to the JavaModel, one by a plugin and one using keyboard input. Only one method, that of the plugin’s, is reported in a detailed manner via a IJavaElementDelta to my IElementChangedListener, the other one does not trigger an elementChanged invocation with such delta. Reproduction steps ------------------ It does not always happen and in fact requires some playing around to reproduce. However, I have managed to reproduce it multiple times and I'm quite positive of the findings. Basically seems that this happens when I time the plugin's and the user's updates to be as "simultaneous" as I can. Any ideas? I really do need to have both methods reported to my IElementChangedListener. Reproducible: Sometimes
Jay, can you please take a look? Thanks!
(In reply to comment #1) > Jay, can you please take a look? Thanks! Hi guys, hate to nag but I was wondering I there were any news. Unfortunately this is a show stopper for my application, thus I'm quite enthusiastic about sorting it out.
(In reply to comment #2) Sorry for the delay on this. Unfortunately, Jay has been on vacation since this bug was opened. If you have zeroed in on the problem please feel free to investigate/post a patch. That will certainly make sure this is fixed sooner. Thanks!
The issue seems to stem from the fact that the JavaModel is being updated from a thread (say, the main thread) other than the reconciler thread, which the documentation neither forbids nor discourages as far as I've read (please feel free to correct me if I'm wrong here). If the thread that has called the JavaModel API gets to CompilationUnit.makeConsistent (which it definitely can) before the reconciler thread does its magic, the reconciler can't detect any changes and fails to report any deltas (since the compilation unit had already been updated by the time the reconciler got to computing the deltas). In my scenario I type in a new method in the editor, note that it does not get reconciled yet because the reconciler thread is deliberately suspended (for the sake of testing the described race condition). Then a new method is created by using the JavaModel API, which in turn triggers a CompilationUnit.makeConsistent, which brings the method I've manually typed in into the compilation unit in order to operate on the up to date model. All this without ever reporting the delta corresponding to the method I've typed in manually (henceforth "the lost delta"). Following is the stack trace that triggered the CompilationUnit.makeConsistent after the JavaModel API had been used. (The reconsiler thread is in a suspended mode in the meanwhile.) Thread [main] (Suspended) CompilationUnit.makeConsistent(IProgressMonitor) line: 1064 CreateMethodOperation(CreateElementInCUOperation).parse(ICompilationUnit) line: 262 CreateMethodOperation(CreateElementInCUOperation).generateNewCompilationUnitAST(ICompilationUnit) line: 164 CreateMethodOperation(CreateElementInCUOperation).executeOperation() line: 127 CreateMethodOperation(JavaModelOperation).run(IProgressMonitor) line: 728 Workspace.run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor) line: 1975 CreateMethodOperation(JavaModelOperation).runOperation(IProgressMonitor) line: 793 SourceType.createMethod(String, IJavaElement, boolean, IProgressMonitor) line: 161 I believe bug 63898 reports a similar problem, though the solution settled for synchronizing only the initialProcess() method of the reconciling flow (using the lock provided by getReconcilerLock()). It would seem that in order to prevent the lost delta scenarios some sort of a synchronization mechanism is in order here. What comes to mind is either invoking the JavaModel API from the reconciler thread (how does one do that?), or synchronizing whatever thread the JavaModel API is invoked from, with the reconcier thread, perhaps by extending the use of the lock provided by getReconcilerLock(). I'd deeply appreciate your comments on this. Thank you in advance.
I will take a look at this now.
Since Jay had to go on unavoidable unplanned time off for several days, this is not ready: retargetting to 3.8 M5.
Created attachment 208774 [details] Testcase Sorry Stas, it has taken me a while to get to this. I am attaching a testcase that I have come up with based on your description on the problem. The testcase has two threads, each trying to modify the same file, albeit in a different way. The first one simulates a editor change and the second one used Java model API. I tried the steps you said, including pausing the first reconciler thread while the second one allowed to run, but I can't quite see the problem. Can you please take a look at the testcase and confirm that this is inline with the scenario you described? Thanks!
Hi Jay, Thanks for taking a look. I'll run this testcase ASAP and get back to you. Meanwhile, I believe my scenario may require some deliberate thread suspending in order for the issue to manifest. I could think of the following breakpoints in order to lure it out. First breakpoint: CompilationUnit class, makeConsistent method Second breakpoint: AbstractReconciler class, run method (say the "process(r);" line) My point being that if the makeConsistent is called first (while the reconciler is in the "process(r);" line) it will mess up the delta state for the "process(r);" once it runs. The documentation (for IOpenable) also seems to mention this: /** * Makes this element consistent with its underlying resource or buffer * by updating the element's structure and properties as necessary. *<p> * Note: Using this functionality on a working copy will interfere with any * subsequent reconciling operation. Indeed, the next * {@link ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)} or * {@link ICompilationUnit#reconcile(int, boolean, boolean, WorkingCopyOwner, IProgressMonitor)} * operation will not account for changes which occurred before an * explicit use of {@link #makeConsistent(IProgressMonitor)} * <p> * @param progress the given progress monitor * @exception JavaModelException if the element is unable to access the contents * of its underlying resource. Reasons include: * <ul> * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li> * </ul> * @see IOpenable#isConsistent() * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor) */ void makeConsistent(IProgressMonitor progress) throws JavaModelException; Your help would be much appreciated.
Created attachment 208850 [details] TestCase results
Created attachment 208851 [details] TestCase results (cont.)
Created attachment 208852 [details] TestCase results (cont.)
Created attachment 208853 [details] TestCase results (cont.)
Created attachment 208854 [details] TestCase results (cont.)
I've attached 5 separate tests case runs, each presents a different result. All 5 runs were red. Hope this helps. Thank you in advance, Stas
(In reply to comment #14) > I've attached 5 separate tests case runs, each presents a different result. > All 5 runs were red. Thanks for that, Stas. Looks like the 2nd and 4th are same failures. And so are the 3rd and 5th. So, we have 3 distinct failures. > The documentation (for IOpenable) also seems to mention this: In fact, the ICompilationUnit#reconcile also mentions this behavior: /** * Reconciles the contents of this working copy, sends out a Java delta * notification indicating the nature of the change of the working copy since * the last time it was either reconciled or made consistent * ({@link IOpenable#makeConsistent(IProgressMonitor)}), and returns a * compilation unit AST if requested. * <p> ... */
Stas, I don't think I will have enough time for this release. Hence moving out of 3.8. If you can come with an approach for the problem and a patch, we can surely consider that.
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant. -- The automated Eclipse Genie.