Openide.text Threading #33165


Author: Miloslav Metelka
Version (revision): 1.0

Abstract: This document searches for improvements in threading model of the openide.text module under issue 33165.
It focuses purely on threading and various functionality descriptions, terminology etc. may be somewhat inaccurate.

Table of Contents
1 Problem
2 Threading Requirements
3 Changes Description
4 Conclusion

1. Problem

Current threading of openide.text does not use Document.render() to read-lock the document during document-related operations.
Because of that number of threading problems may arise. Issue 33040 is likely the most noticeable and unpleasant one.

2. Threading Requirements

Functionality Overview

Main functionality building blocks of the openide.text include

  1. Creation of empty Swing document for a particular fileobject (dataobject)
  2. Loading of contents of the fileobject into that empty document
  3. Closing of the existing document
  4. Automatic reloading of the document in case an external modification of the related fileobject occurs.
  5. Conversion of position refs to/from memory kind once a document is loaded/closed.

Main Methods Overview

Requirements Possibly Affecting Locking

3. Changes Description

The following changes have been done:

4. Conclusion

The changes presented here should improve the threading of the openide.text package only. To achieve correct behavior completely all the code accessing a document instance (usually through methods in openide.text) in the modules would have to be reviewed whether it's properly read-locked (e.g. the annotations implementations such as JavaEditor.processAnnotations()).
Still the current changes in openide.text should partly help even in those cases because they will read-lock the document at least for the time when they are being called in the target module's code.

There are still architectural issues to think about. For example in the existing openide.text design if someone calls openDocument() and e.g. write-locks the returned document instance and then starts to modify it then it should also attach the change listener to the CloneableEditorSupport to be notified that the document being changed was closed by another thread and that it is no longer valid. In case the notification comes the work done in the document should be abandoned and likely redone in the new document.
Otherwise it may happen that the modifications are done to the document no longer being valid.
The problem is that the notification about closing of the document can currently come anytime so theoretically the document could be closed but more importantly saved with just partial changes (because of the notifyModify() gets called during closing).
We could try to improve the situation by running the closeDocument() under write-lock on the document being closed. However to prevent deadlocks we should first write-lock the document obtained by previous call to getDocument() and then use CES.getLock() and do the document closing.
Even with that it's still possible that the document is closed between the moment when thread obtains the document instance by openDocument() and the moment when thread write-locks the document for modification.
However to fix this case we could set a property in the document once it closed e.g. doc.putProperty("closed", Boolean.TRUE). The property would only have to be checked once right after the write-lock (or read-lock) was obtained on the document returned from openDocument().