Git history page: move expensive operations in the background
commit0da9aa76e5fb1f2af437d9b21f87bb66f0e15c96
authorThomas Wolf <thomas.wolf@paranor.ch>
Tue, 26 Jun 2018 20:44:45 +0000 (26 22:44 +0200)
committerThomas Wolf <thomas.wolf@paranor.ch>
Sun, 15 Jul 2018 13:46:53 +0000 (15 15:46 +0200)
tree0a9c57dd51cb7211e39b11bdfcbd2ffe812002f3
parent70d01ef871f64de26390f243613beb5ad6ac8978
Git history page: move expensive operations in the background

There were still two potentially expensive operations occurring in the
UI thread:

* Computing the file diffs can take quite a while for large commits.
* Preparing to load the history can take quite a while if there are
  many refs.

Because of the highly asynchronous loading already going on for other
things (commit messages, unified file diffs, actually loading the
history) and the somewhat hacky way the various viewers were re-set
when something changed, it was not possible to do this in several
commits and still have everything working correctly. The old code
stored the repository to use before the new history was loaded, which
sometimes could lead to cases where EGit would end up looking for an
object in the wrong repository when the repository had changed.

Concerning file diffs: we exploit the fact that since commit 9df32ed
a FileDiff carries its repository, and we wrap all items needed to
compute the file diffs in a FileDiffInput object (tree walk, repo,
interesting paths, and so on). The diff calculation is done newly
in a background job, and only the actual update of the viewer happens
in the UI thread. Because the diff computation is now asynchronous,
revealing and selecting interesting elements had to be moved to this
UI update triggered by the background job. Incidentally this part of
the code became much simpler.

One problem here is that computing diffs is not cancelable in JGit.
The background jobs must be serialized because they may re-use the same
TreeWalk instance. This may lead to longer delays than desired until
the file diff viewer updates, but at least he UI will not be blocked.
To remedy this fully, DiffEntry.scan() and RenameDetector.compute() in
JGit should be made cancelable. See bug 536323 and bug 536324.

Concerning the history preparation: marking the start points for the
RevWalk can be a rather expensive operation if there are many refs.
Use a customized RevWalk for the history that does this on the very
first call to next(). That way it gets executed in the
GenerateHistoryJob instead of in the UI thread.

For the commit message viewer, a similar problem with trying to look
up a commit in the wrong repository became apparent. This was resolved
by not storing the repo in the viewer itself but relying on the fact
that an SWTCommit also carries its repository along.

Finally, asynchronously loading the history meant that there was some
time during which some parts of the git history page had already been
prepared for a new repository now being loaded, but the table would
still show the old entries. During that time a user could select one of
these old commits and try to invoke commands on it, which then also
could result in looking up a commit in the wrong repository. This is
resolved now by clearing the table when the repository changes.

Bug: 440588
Bug: 485743
Change-Id: I5c3cf9a7a0ae536000a9bf4542407fea0b741e22
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
13 files changed:
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/CommitEditorPage.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/RepositoryCommit.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/StashEditorPage.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiff.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiffContentProvider.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiffInput.java [new file with mode: 0644]
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryWalk.java [new file with mode: 0644]
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/SWTCommit.java
org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties