myInterrupters.add(new Pair<String, Runnable>(name, runnable));
return true;
}
- }
+ }
public void projectOpened(Project project) {
synchronized (ourLock) {
import com.intellij.ide.highlighter.WorkspaceFileType;
import com.intellij.lifecycle.AtomicSectionsAware;
-import com.intellij.lifecycle.ControlledAlarmFactory;
-import com.intellij.lifecycle.SlowlyClosingAlarm;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationDisplayType;
-import com.intellij.notification.NotificationType;
-import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ProjectComponent;
final VcsInvalidated invalidated = dirtyScopeManager.retrieveScopes();
if (invalidated == null || invalidated.isEmpty()) {
// a hack here; but otherwise everything here should be refactored ;)
- if (invalidated.isEmpty() && invalidated.isEverythingDirty()) {
+ if (invalidated != null && invalidated.isEmpty() && invalidated.isEverythingDirty()) {
VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty();
}
return;
}
private static class MyChangesDeltaForwarder implements PlusMinus<Pair<String, AbstractVcs>> {
- private SlowlyClosingAlarm myAlarm;
+ //private SlowlyClosingAlarm myAlarm;
private RemoteRevisionsCache myRevisionsCache;
private final ProjectLevelVcsManager myVcsManager;
+ private ExecutorWrapper myExecutorWrapper;
+ private final ExecutorService myService;
+
public MyChangesDeltaForwarder(final Project project, final ExecutorService service) {
- myAlarm = ControlledAlarmFactory.createOnSharedThread(project, "changes delta consumer forwarder", service);
+ myService = service;
+ //myAlarm = ControlledAlarmFactory.createOnSharedThread(project, UpdateRequestsQueue.LOCAL_CHANGES_UPDATE, service);
+ myExecutorWrapper = new ExecutorWrapper(project, UpdateRequestsQueue.LOCAL_CHANGES_UPDATE);
myRevisionsCache = RemoteRevisionsCache.getInstance(project);
myVcsManager = ProjectLevelVcsManager.getInstance(project);
}
public void plus(final Pair<String, AbstractVcs> stringAbstractVcsPair) {
- myAlarm.addRequest(new Runnable() {
+ myService.submit(new Runnable() {
public void run() {
- myRevisionsCache.plus(getCorrectedPair(stringAbstractVcsPair));
+ myExecutorWrapper.submit(new Consumer<AtomicSectionsAware>() {
+ public void consume(AtomicSectionsAware atomicSectionsAware) {
+ myRevisionsCache.plus(getCorrectedPair(stringAbstractVcsPair));
+ }
+ });
}
});
}
public void minus(final Pair<String, AbstractVcs> stringAbstractVcsPair) {
- myAlarm.addRequest(new Runnable() {
+ myService.submit(new Runnable() {
public void run() {
+ myExecutorWrapper.submit(new Consumer<AtomicSectionsAware>() {
+ public void consume(AtomicSectionsAware atomicSectionsAware) {
+ myRevisionsCache.minus(getCorrectedPair(stringAbstractVcsPair));
+ }
+ });
myRevisionsCache.minus(getCorrectedPair(stringAbstractVcsPair));
}
});
--- /dev/null
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.changes;
+
+import com.intellij.lifecycle.AtomicSectionsAware;
+import com.intellij.lifecycle.PeriodicalTasksCloser;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.Consumer;
+import com.intellij.util.concurrency.Semaphore;
+
+/**
+ * for restarted single threaded executor
+ */
+public class ExecutorWrapper {
+ private final Project myProject;
+ private final String myName;
+ private final Semaphore mySemaphore;
+ private volatile boolean myDisposeStarted;
+ private final Object myLock;
+ private boolean myInProgress;
+ private Runnable myStopper;
+ private AtomicSectionsAware myAtomicSectionsAware;
+
+ protected ExecutorWrapper(final Project project, final String name) {
+ myProject = project;
+ myName = name;
+ myLock = new Object();
+ mySemaphore = new Semaphore();
+
+ myStopper = new Runnable() {
+ public void run() {
+ synchronized (myLock) {
+ myDisposeStarted = true;
+ taskFinished();
+ }
+ }
+ };
+
+ myAtomicSectionsAware = new AtomicSectionsAware() {
+ public void checkShouldExit() throws ProcessCanceledException {
+ if (myDisposeStarted) {
+ throw new ProcessCanceledException();
+ }
+ }
+ public void enter() {
+ // we won't kill the thread, so we can ignore information
+ }
+ public void exit() {
+ //the same
+ }
+ public boolean shouldExitAsap() {
+ return myDisposeStarted;
+ }
+ };
+ myDisposeStarted = ! PeriodicalTasksCloser.getInstance(myProject).register(myName, myStopper);
+ }
+
+ private void taskFinished() {
+ synchronized (myLock) {
+ if (myInProgress) {
+ myInProgress = false;
+ mySemaphore.up();
+ }
+ }
+ }
+
+ /**
+ * executed on separate thread, that can be interrupted immediately, while "the main thread" gets control back
+ * and can continue to serve other requests
+ */
+ public void submit(final Consumer<AtomicSectionsAware> runnable) {
+ try {
+ synchronized (myLock) {
+ if (myDisposeStarted) return;
+ assert ! myInProgress;
+ myInProgress = true;
+ mySemaphore.down();
+ }
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ public void run() {
+ try {
+ runnable.consume(myAtomicSectionsAware);
+ } finally {
+ taskFinished();
+ }
+ }
+ });
+ mySemaphore.waitFor();
+ } finally {
+ taskFinished();
+ }
+ }
+}
final VirtualFile root = getRootForPath(pair.getFirst());
if (root == null) return;
synchronized (myLock) {
- myQueries.removeValue(new VcsRoot(pair.getSecond(), root), pair.getFirst());
+ final VcsRoot key = new VcsRoot(pair.getSecond(), root);
+ if (myQueries.containsKey(key)) {
+ myQueries.removeValue(key, pair.getFirst());
+ }
myChanged.remove(pair.getFirst());
}
}
package com.intellij.openapi.vcs.changes;
import com.intellij.ide.startup.impl.StartupManagerImpl;
-import com.intellij.lifecycle.ControlledAlarmFactory;
-import com.intellij.lifecycle.ScheduledSlowlyClosingAlarm;
+import com.intellij.lifecycle.AtomicSectionsAware;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.util.Consumer;
+import org.jetbrains.annotations.NonNls;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
/**
* ChangeListManager updates scheduler.
public class UpdateRequestsQueue {
private final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.UpdateRequestsQueue");
private final Project myProject;
+ private final ScheduledExecutorService myExecutor;
private final LocalChangesUpdater myDelegate;
private final Object myLock;
private volatile boolean myStarted;
private final List<Runnable> myWaitingUpdateCompletionQueue;
private final ProjectLevelVcsManager myPlVcsManager;
private boolean myUpdateUnversionedRequested;
- private final ScheduledSlowlyClosingAlarm mySharedExecutor;
+ //private final ScheduledSlowlyClosingAlarm mySharedExecutor;
private final StartupManager myStartupManager;
+ private final ExecutorWrapper myExecutorWrapper;
+ @NonNls public static final String LOCAL_CHANGES_UPDATE = "Local changes update";
public UpdateRequestsQueue(final Project project, final ScheduledExecutorService executor, final LocalChangesUpdater delegate) {
- mySharedExecutor = ControlledAlarmFactory.createScheduledOnSharedThread(project, "Local changes update", executor);
+ myProject = project;
+ myExecutor = executor;
+
+ //mySharedExecutor = ControlledAlarmFactory.createScheduledOnSharedThread(project, LOCAL_CHANGES_UPDATE, executor);
+ myExecutorWrapper = new ExecutorWrapper(myProject, LOCAL_CHANGES_UPDATE);
myDelegate = delegate;
- myProject = project;
myPlVcsManager = ProjectLevelVcsManager.getInstance(myProject);
myStartupManager = StartupManager.getInstance(myProject);
myLock = new Object();
if (! myRequestSubmitted) {
final MyRunnable runnable = new MyRunnable();
myRequestSubmitted = true;
- mySharedExecutor.addRequest(runnable, 300);
+ myExecutor.schedule(runnable, 300, TimeUnit.MILLISECONDS);
LOG.debug("Scheduled for project: " + myProject.getName() + ", runnable: " + runnable.hashCode());
myUpdateUnversionedRequested |= updateUnversionedFiles;
} else if (updateUnversionedFiles && (! myUpdateUnversionedRequested)) {
private class MyRunnable implements Runnable {
public void run() {
- boolean updateUnversioned;
+ final boolean updateUnversioned;
final List<Runnable> copy = new ArrayList<Runnable>(myWaitingUpdateCompletionQueue.size());
try {
}
LOG.debug("MyRunnable: INVOKE, project: " + myProject.getName() + ", runnable: " + hashCode());
- myDelegate.execute(updateUnversioned, mySharedExecutor);
+ myExecutorWrapper.submit(new Consumer<AtomicSectionsAware>() {
+ public void consume(AtomicSectionsAware atomicSectionsAware) {
+ myDelegate.execute(updateUnversioned, atomicSectionsAware);
+ }
+ });
LOG.debug("MyRunnable: invokeD, project: " + myProject.getName() + ", runnable: " + hashCode());
} finally {
synchronized (myLock) {