VCS: conflicts tracker's document listener actions were buffered and moved onto background thread. review=dmitry avdeev

This commit is contained in:
irengrig
2011-01-25 18:50:13 +03:00
parent 3ff87ad2d8
commit 441989ab39
4 changed files with 81 additions and 39 deletions
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.progress.SomeQueue;
import com.intellij.util.Alarm;
@@ -25,9 +26,13 @@ public class ZipperUpdater {
private final Object myLock = new Object();
private final int myDelay;
public ZipperUpdater(final int delay) {
public ZipperUpdater(final int delay, Disposable parentDisposable) {
this(delay, Alarm.ThreadToUse.SHARED_THREAD, parentDisposable);
}
public ZipperUpdater(final int delay, final Alarm.ThreadToUse threadToUse, Disposable parentDisposable) {
myDelay = delay;
myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
myAlarm = new Alarm(threadToUse, parentDisposable);
}
public void queue(final Runnable runnable) {
@@ -36,16 +41,19 @@ public class ZipperUpdater {
public void queue(final Runnable runnable, final boolean urgent) {
synchronized (myLock) {
final boolean wasRaised = myRaised;
myRaised = true;
}
myAlarm.addRequest(new Runnable() {
public void run() {
synchronized (myLock) {
if (! myRaised) return;
myRaised = false;
}
runnable.run();
if (! wasRaised) {
myAlarm.addRequest(new Runnable() {
public void run() {
synchronized (myLock) {
if (! myRaised) return;
myRaised = false;
}
runnable.run();
}
}, urgent ? 0 : myDelay);
}
}, urgent ? 0 : myDelay);
}
}
}
@@ -16,6 +16,8 @@
package com.intellij.openapi.vcs.changes.conflicts;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
@@ -24,12 +26,15 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vcs.ZipperUpdater;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.EditorNotifications;
import com.intellij.util.Alarm;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashSet;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
@@ -38,6 +43,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Dmitry Avdeev
@@ -57,6 +63,8 @@ public class ChangelistConflictTracker {
private final DocumentAdapter myDocumentListener;
private final FileStatusManager myFileStatusManager;
private final Set<VirtualFile> myCheckSet;
private final Object myCheckSetLock;
public ChangelistConflictTracker(Project project,
ChangeListManager changeListManager,
@@ -68,7 +76,26 @@ public class ChangelistConflictTracker {
myEditorNotifications = editorNotifications;
myDocumentManager = FileDocumentManager.getInstance();
myFileStatusManager = fileStatusManager;
myCheckSetLock = new Object();
myCheckSet = new HashSet<VirtualFile>();
final Application application = ApplicationManager.getApplication();
final ZipperUpdater zipperUpdater = new ZipperUpdater(300, Alarm.ThreadToUse.SHARED_THREAD, myProject);
final Runnable runnable = new Runnable() {
@Override
public void run() {
if (application.isDisposed() || myProject.isDisposed() || (! myProject.isOpen())) return;
final Set<VirtualFile> localSet;
synchronized (myCheckSetLock) {
localSet = new HashSet<VirtualFile>();
localSet.addAll(myCheckSet);
myCheckSet.clear();
}
for (VirtualFile file : localSet) {
checkFile(file);
}
}
};
myDocumentListener = new DocumentAdapter() {
@Override
public void documentChanged(DocumentEvent e) {
@@ -77,31 +104,10 @@ public class ChangelistConflictTracker {
}
Document document = e.getDocument();
final VirtualFile file = myDocumentManager.getFile(document);
if (file == null || isFromActiveChangelist(file) || ChangesUtil.isInternalOperation(file)) {
return;
synchronized (myCheckSetLock) {
myCheckSet.add(file);
}
myChangeListManager.invokeAfterUpdate(new Runnable() {
public void run() {
if (!isFromActiveChangelist(file)) {
String path = file.getPath();
Conflict conflict = myConflicts.get(path);
boolean newConflict = false;
if (conflict == null) {
conflict = new Conflict();
myConflicts.put(path, conflict);
newConflict = true;
}
conflict.timestamp = System.currentTimeMillis();
conflict.changelistId = myChangeListManager.getDefaultChangeList().getId();
if (newConflict && myOptions.HIGHLIGHT_CONFLICTS) {
myFileStatusManager.fileStatusChanged(file);
myEditorNotifications.updateNotifications(file);
}
}
}
}, InvokeAfterUpdateMode.SILENT, null, null);
zipperUpdater.queue(runnable);
}
};
@@ -128,6 +134,34 @@ public class ChangelistConflictTracker {
};
}
private void checkFile(final VirtualFile file) {
if (file == null || isFromActiveChangelist(file) || ChangesUtil.isInternalOperation(file)) {
return;
}
myChangeListManager.invokeAfterUpdate(new Runnable() {
public void run() {
if (!isFromActiveChangelist(file)) {
String path = file.getPath();
Conflict conflict = myConflicts.get(path);
boolean newConflict = false;
if (conflict == null) {
conflict = new Conflict();
myConflicts.put(path, conflict);
newConflict = true;
}
conflict.timestamp = System.currentTimeMillis();
conflict.changelistId = myChangeListManager.getDefaultChangeList().getId();
if (newConflict && myOptions.HIGHLIGHT_CONFLICTS) {
myFileStatusManager.fileStatusChanged(file);
myEditorNotifications.updateNotifications(file);
}
}
}
}, InvokeAfterUpdateMode.SILENT, null, null);
}
public boolean isWritingAllowed(@NotNull VirtualFile file) {
if (isFromActiveChangelist(file)) return true;
Conflict conflict = myConflicts.get(file.getPath());
@@ -103,7 +103,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
});
myProject = project;
myLoadQueue = new ZipperUpdater(500);
myLoadQueue = new ZipperUpdater(500, getDisposable());
myPatches = new LinkedList<FilePatchInProgress>();
myRecentPathFileChange = new AtomicReference<FilePresentation>();
myChangesTreeList = new MyChangeTreeList(project, Collections.<FilePatchInProgress.PatchChange>emptyList(),
@@ -20,15 +20,15 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsListener;
import com.intellij.openapi.vcs.ZipperUpdater;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.integrate.Merger;
import org.jetbrains.idea.svn.dialogs.SvnMapDialog;
import org.jetbrains.idea.svn.integrate.Merger;
import org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache;
import java.util.ArrayList;
@@ -45,7 +45,7 @@ public class MergeInfoUpdatesListener {
public MergeInfoUpdatesListener(final Project project, final MessageBusConnection connection) {
myConnection = connection;
myProject = project;
myUpdater = new ZipperUpdater(DELAY);
myUpdater = new ZipperUpdater(DELAY, myProject);
}
public void addPanel(final RootsAndBranches action) {