Bug 228961 - [api] improve ITextFileBuffer.getAnnotationModel()
Summary: [api] improve ITextFileBuffer.getAnnotationModel()
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 3.4   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 3.5 M2   Edit
Assignee: Platform-Text-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: api
Depends on: 69289
Blocks:
  Show dependency tree
 
Reported: 2008-04-25 17:42 EDT by Min Idzelis CLA
Modified: 2008-09-12 09:55 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Min Idzelis CLA 2008-04-25 17:42:49 EDT
Build ID: Eclipse 3.4M6a

Steps To Reproduce:
I am seeing the following stack trace in my code:

java.lang.NullPointerException
at org.eclipse.jface.text.source.AnnotationModel.connect(AnnotationModel.java:513)
at org.eclipse.core.internal.filebuffers.ResourceTextFileBuffer.getAnnotationModel(ResourceTextFileBuffer.java:152)
<snip>

I think there is a thread-safety issue with both subclasses of ITextFileBuffer. 

This is what I'm doing:

I was listening to a buffer create. I stashed away the buffer for later use. 

The thing that created the buffer is doing its thing on say, Thread A.

My Thread B comes along and says... hey, I need some info from the annotations associated with the file. So it lookes at the stashed away buffer and does getAnnotationModel(). getAnnotationModel() starts doing a connect().

In the mean time, Thread A is done with the buffer, and i assume, disposes it 

But connect() was in the middle of doing something... it tries to add a listener to the fDocument but it can't because it's already null because it was disposed. 

The solution is that I think ResourceTextFileBuffer (and the other one) needs to protect it's dispose() method using the same fAnnotationModelCreationLock lock that it uses for the getAnnotationModel(). Well, not the *whole* dispose method, but the section that is disposing the annotation model. 

More information:
Comment 1 Dani Megert CLA 2008-04-26 07:53:11 EDT
Please read Javadoc of IFileBuffer:

 * It is not specified whether simultaneous editing sessions can be owned by
 * different threads.
 * </p>
 
What could help you is:

org.eclipse.core.filebuffers.manipulation.GenericFileBufferOperationRunner
org.eclipse.core.filebuffers.manipulation.IFileBufferOperation

See also: org.eclipse.core.filebuffers.ISynchronizationContext
Comment 2 Min Idzelis CLA 2008-04-28 22:33:48 EDT
What you've suggested won't help me. The javadocs for IFileBufferOperation state that 

 * A file buffer operation performs changes of the contents of a file buffer.

I'm not changing the contents of the IFileBuffer at all. Additionally, the IFileBufferOperation  will commit() the buffer which would be very bad for performance since I'm simply trying to read it. 

The other two files you mentioned seem to be related to the execution of the IFileBufferOperation. 

Also, in the javadoc quoted here: 
 * It is not specified whether simultaneous editing sessions can be owned by
 * different threads.
 
It is referring to simultaneous *editing* sessions. I wouldn't consider calling getAnnotationModel() to be an *editing* operation. 

I believe there are two categories of manipulating buffers. Lifecycle operations (create/dispose) and character manipulation, the later of which I *would* consider a edit op.  

Let me restate my problem. 

I'm simply trying to read the annotations for a file buffer. 

I have an IFileBufferListener that listens to create/dispose events. On create/dispose it will register/deregister a IDocument listener to the document associated with the IFileBuffer. Additionally, it adds ITextFileBuffer to a map when created and removed it when disposed. 

The document listener updates/creates positions and annotations if the file changes while it is open. 

A background processing thread needs to query these annotations (if they are present.) 

If the background processing thread enters the ITextFileBuffer.getAnnotationModel() while similtaneously the ITextFileBuffer is disposed(), the getAnnotationModel() throws a very uninformative and unwanted NullPointerException. 

It seems that a little adding a bit of thread safety to the *lifecycle* manipulations of a IFileBuffer would be the way to solve this. 

(I could call getAnnotationModel at the time of create() but that also seems like it would be a very bad performance hit - as I'm listening to *all* ITextFileBuffers)
Comment 3 Dani Megert CLA 2008-04-29 02:45:58 EDT
Maybe you already noticed, but the annotation model itself is currently also not thread-safe (see bug 69289).

In your case the best bet for now is to run your code that gets the annotation model in the UI thread.

Reopening as the current API for getAnnotationModel() is not clear, e.g. it doesn't spec that 'null' might be returned.
Comment 4 Min Idzelis CLA 2008-04-29 09:06:11 EDT
(In reply to comment #3)
> Maybe you already noticed, but the annotation model itself is currently also
> not thread-safe (see bug 69289).
> 
> In your case the best bet for now is to run your code that gets the annotation
> model in the UI thread.


What is special about the UI thread? It seems to me that FileBuffers.getTextFileBufferManager().disconnect() can and *does* get called from the non-UI thread. If this happens, even if I'm calling getAnnotationModel() in the UI thread, I will still have the same problem. Only if *everybody* that accessed the getTextFileBufferManager() did so from same thread would it work. 


> Reopening as the current API for getAnnotationModel() is not clear, e.g. it
> doesn't spec that 'null' might be returned.
> 

If 'null' was being returned, I'd be happy. But what is happening is a NullPointerException is being thrown. 
Comment 5 Dani Megert CLA 2008-09-12 09:55:08 EDT
Fixed in HEAD (adjusted Javadoc and made AnnotationModel.connect(...) more stable.
Available in builds > N20080911-2000.