summaryrefslogtreecommitdiff
path: root/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java')
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java383
1 files changed, 151 insertions, 232 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
index f71eb5fef698..a20df87718cc 100644
--- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
@@ -17,8 +17,6 @@ package com.intellij.openapi.project;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.caches.CacheUpdater;
-import com.intellij.ide.caches.FileContent;
-import com.intellij.ide.util.DelegatingProgressIndicator;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -29,40 +27,47 @@ import com.intellij.openapi.progress.*;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ShutDownTracker;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.AppIconScheme;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.openapi.wm.ex.StatusBarEx;
+import com.intellij.psi.impl.DebugUtil;
import com.intellij.ui.AppIcon;
import com.intellij.util.concurrency.Semaphore;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Queue;
import com.intellij.util.io.storage.HeavyProcessLatch;
-import com.intellij.util.messages.MessageBus;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
+import java.util.Map;
-public class DumbServiceImpl extends DumbService {
+public class DumbServiceImpl extends DumbService implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.DumbServiceImpl");
private volatile boolean myDumb = false;
private final DumbModeListener myPublisher;
- private final Queue<IndexUpdateRunnable> myUpdatesQueue = new Queue<IndexUpdateRunnable>(5);
+ private final Queue<DumbModeTask> myUpdatesQueue = new Queue<DumbModeTask>(5);
+
+ /**
+ * Per-task progress indicators. Modified from EDT only.
+ * The task is removed from this map after it's finished or when the project is disposed.
+ */
+ private final Map<DumbModeTask, ProgressIndicatorEx> myProgresses = ContainerUtil.newConcurrentMap();
+
private final Queue<Runnable> myRunWhenSmartQueue = new Queue<Runnable>(5);
private final Project myProject;
- private final CacheUpdateRunner NULL_ACTION;
+
+ public DumbServiceImpl(Project project) {
+ myProject = project;
+ myPublisher = project.getMessageBus().syncPublisher(DUMB_MODE);
+ }
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"})
public static DumbServiceImpl getInstance(@NotNull Project project) {
@@ -70,46 +75,28 @@ public class DumbServiceImpl extends DumbService {
}
@Override
- public void queueTask(final DumbModeTask task) {
- CacheUpdater wrapper = new CacheUpdater() {
- @Override
- public int getNumberOfPendingUpdateJobs() {
- return 0;
- }
-
- @NotNull
- @Override
- public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) {
- task.performInDumbMode(indicator);
- return new VirtualFile[0];
- }
-
- @Override
- public void processFile(@NotNull FileContent fileContent) {
-
- }
-
- @Override
- public void updatingDone() {
- }
-
- @Override
- public void canceled() {
-
- }
+ public void queueTask(@NotNull final DumbModeTask task) {
+ scheduleCacheUpdate(task, true);
+ }
- @Override
- public String toString() {
- return task.toString();
- }
- };
- queueCacheUpdateInDumbMode(Arrays.asList(wrapper));
+ @Override
+ public void cancelTask(@NotNull DumbModeTask task) {
+ if (ApplicationManager.getApplication().isInternal()) LOG.info("cancel " + task + "\n" + DebugUtil.currentStackTrace());
+ ProgressIndicatorEx indicator = myProgresses.get(task);
+ if (indicator != null) {
+ indicator.cancel();
+ }
}
- public DumbServiceImpl(Project project, MessageBus bus) {
- myProject = project;
- myPublisher = bus.syncPublisher(DUMB_MODE);
- NULL_ACTION = new CacheUpdateRunner(project, Collections.<CacheUpdater>emptyList());
+ @Override
+ public void dispose() {
+ ApplicationManager.getApplication().assertIsDispatchThread();
+ myUpdatesQueue.clear();
+ myRunWhenSmartQueue.clear();
+ for (DumbModeTask task : new ArrayList<DumbModeTask>(myProgresses.keySet())) {
+ cancelTask(task);
+ Disposer.dispose(task);
+ }
}
@Override
@@ -145,87 +132,58 @@ public class DumbServiceImpl extends DumbService {
}
}
+ @SuppressWarnings("deprecation")
public void queueCacheUpdate(@NotNull Collection<CacheUpdater> updaters) {
- scheduleCacheUpdate(updaters, false);
+ scheduleCacheUpdate(new CacheUpdateRunner(myProject, new ArrayList<CacheUpdater>(updaters)), false);
}
+ @SuppressWarnings("deprecation")
public void queueCacheUpdateInDumbMode(@NotNull Collection<CacheUpdater> updaters) {
- scheduleCacheUpdate(updaters, true);
+ scheduleCacheUpdate(new CacheUpdateRunner(myProject, new ArrayList<CacheUpdater>(updaters)), true);
}
- private void scheduleCacheUpdate(@NotNull Collection<CacheUpdater> updaters, boolean forceDumbMode) {
- // prevent concurrent modifications
- final CacheUpdateRunner runner = new CacheUpdateRunner(myProject, new ArrayList<CacheUpdater>(updaters));
-
+ private void scheduleCacheUpdate(@NotNull final DumbModeTask task, boolean forceDumbMode) {
+ if (ApplicationManager.getApplication().isInternal()) LOG.info("schedule " + task);
final Application application = ApplicationManager.getApplication();
- if (application.isUnitTestMode() || application.isHeadlessEnvironment()) {
- // no dumb mode for tests
- EmptyProgressIndicator i = new EmptyProgressIndicator();
- final int size = runner.queryNeededFiles(i);
+ if (application.isUnitTestMode() ||
+ application.isHeadlessEnvironment() ||
+ !forceDumbMode && !myDumb && application.isReadAccessAllowed()) {
+ final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
+ if (indicator != null) {
+ indicator.pushState();
+ }
try {
HeavyProcessLatch.INSTANCE.processStarted();
- if (size > 0) {
- runner.processFiles(i, false);
- }
- runner.updatingDone();
+ task.performInDumbMode(indicator != null ? indicator : new EmptyProgressIndicator());
}
finally {
HeavyProcessLatch.INSTANCE.processFinished();
- }
- return;
- }
-
- if (!forceDumbMode && !myDumb && application.isReadAccessAllowed()) {
- // if there are not so many files to process, process them on the spot without entering dumb mode
- final ProgressIndicator currentIndicator = ProgressManager.getInstance().getProgressIndicator();
- final ProgressIndicator indicator;
- if (currentIndicator != null) {
- indicator = currentIndicator;
- currentIndicator.pushState();
- }
- else {
- indicator = new EmptyProgressIndicator();
- }
- try {
- final int size = runner.queryNeededFiles(indicator);
- if (size + runner.getNumberOfPendingUpdateJobs(indicator) < 50) {
- // If not that many files found, process them on the spot, avoiding entering dumb mode
- // Consider number of pending tasks as well, because they may take noticeable time to process even if the number of files is small
- try {
- HeavyProcessLatch.INSTANCE.processStarted();
- if (size > 0) {
- runner.processFiles(indicator, false);
- }
- runner.updatingDone();
- }
- finally {
- HeavyProcessLatch.INSTANCE.processFinished();
- }
- return;
- }
- }
- finally {
- if (currentIndicator != null) {
- currentIndicator.popState();
+ if (indicator != null) {
+ indicator.popState();
}
+ Disposer.dispose(task);
}
+ return;
}
-
- final IndexUpdateRunnable updateRunnable = new IndexUpdateRunnable(runner);
-
UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() {
@Override
public void run() {
if (myProject.isDisposed()) {
return;
}
+ final ProgressIndicatorBase indicator = new ProgressIndicatorBase();
+ myProgresses.put(task, indicator);
+ Disposer.register(task, new Disposable() {
+ @Override
+ public void dispose() {
+ application.assertIsDispatchThread();
+ myProgresses.remove(task);
+ }
+ });
// ok to test and set the flag like this, because the change is always done from dispatch thread
- if (myDumb) {
- myUpdatesQueue.addLast(updateRunnable);
- }
- else {
+ if (!myDumb) {
// always change dumb status inside write action.
// This will ensure all active read actions are completed before the app goes dumb
boolean startSuccess =
@@ -239,14 +197,13 @@ public class DumbServiceImpl extends DumbService {
catch (Throwable e) {
LOG.error(e);
}
- finally {
- try {
- updateRunnable.run();
- }
- catch (Throwable e) {
- LOG.error("Failed to start background index update task", e);
- return false;
- }
+
+ try {
+ startBackgroundProcess(task, indicator);
+ }
+ catch (Throwable e) {
+ LOG.error("Failed to start background index update task", e);
+ return false;
}
return true;
}
@@ -255,6 +212,9 @@ public class DumbServiceImpl extends DumbService {
updateFinished();
}
}
+ else {
+ myUpdatesQueue.addLast(task);
+ }
}
});
}
@@ -365,140 +325,99 @@ public class DumbServiceImpl extends DumbService {
}, modalityState, myProject.getDisposed());
}
- private class IndexUpdateRunnable implements Runnable {
- private final CacheUpdateRunner myAction;
+ private void startBackgroundProcess(@NotNull final DumbModeTask task, @NotNull final ProgressIndicatorEx indicator) {
+ ProgressManager.getInstance().run(new Task.Backgroundable(myProject, IdeBundle.message("progress.indexing"), false) {
- public IndexUpdateRunnable(@NotNull CacheUpdateRunner action) {
- myAction = action;
- }
+ @Override
+ public void run(@NotNull final ProgressIndicator visibleIndicator) {
+ if (ApplicationManager.getApplication().isInternal()) LOG.info("Running dumb mode task: " + task);
+
+ final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance();
+ final Thread self = Thread.currentThread();
+ try {
+ HeavyProcessLatch.INSTANCE.processStarted();
+ shutdownTracker.registerStopperThread(self);
- @Override
- public void run() {
- ProgressManager.getInstance().run(new Task.Backgroundable(myProject, IdeBundle.message("progress.indexing"), false) {
+ indicator.checkCanceled();
- @Override
- public void run(@NotNull final ProgressIndicator indicator) {
- if (indicator instanceof ProgressIndicatorEx) {
- ((ProgressIndicatorEx)indicator).addStateDelegate(new ProgressIndicatorBase() {
- double lastFraction;
+ if (visibleIndicator instanceof ProgressIndicatorEx) {
+ indicator.addStateDelegate((ProgressIndicatorEx)visibleIndicator);
+ ((ProgressIndicatorEx)visibleIndicator).addStateDelegate(new AppIconProgress());
+ }
- @Override
- public void setFraction(final double fraction) {
- if (fraction - lastFraction < 0.01d) return;
- lastFraction = fraction;
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- AppIcon.getInstance().setProgress(myProject, "indexUpdate", AppIconScheme.Progress.INDEXING, fraction, true);
- }
- });
- }
+ indicator.setIndeterminate(true);
+ indicator.setText(IdeBundle.message("progress.indexing.scanning"));
- @Override
- public void finish(@NotNull TaskInfo task) {
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- AppIcon appIcon = AppIcon.getInstance();
- if (appIcon.hideProgress(myProject, "indexUpdate")) {
- appIcon.requestAttention(myProject, false);
- appIcon.setOkBadge(myProject, true);
- }
- }
- });
- }
- });
- }
+ task.performInDumbMode(indicator);
+ }
+ catch (ProcessCanceledException ignored) {
+ }
+ catch (Throwable unexpected) {
+ LOG.error(unexpected);
+ }
+ finally {
+ shutdownTracker.unregisterStopperThread(self);
+ HeavyProcessLatch.INSTANCE.processFinished();
+ taskFinished(task);
+ }
+ }
+ });
+ }
- final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator);
+ private void taskFinished(@NotNull final DumbModeTask prevTask) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ if (myProject.isDisposed()) return;
+ Disposer.dispose(prevTask);
- final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance();
- final Thread self = Thread.currentThread();
- try {
- HeavyProcessLatch.INSTANCE.processStarted();
- shutdownTracker.registerStopperThread(self);
- runAction(proxy, myAction);
- }
- catch (RuntimeException e) {
- LOG.error(e);
- throw e;
- }
- finally {
- shutdownTracker.unregisterStopperThread(self);
- HeavyProcessLatch.INSTANCE.processFinished();
+ while (true) {
+ if (myUpdatesQueue.isEmpty()) {
+ updateFinished();
+ return;
}
- }
- private void runAction(ProgressIndicator indicator, CacheUpdateRunner updateRunner) {
- while (updateRunner != null) {
- try {
- if (ApplicationManager.getApplication().isInternal()) LOG.info("Running dumb mode task: " + updateRunner);
- indicator.checkCanceled();
- indicator.setIndeterminate(true);
- indicator.setText(IdeBundle.message("progress.indexing.scanning"));
- int count = updateRunner.queryNeededFiles(indicator);
-
- indicator.setIndeterminate(false);
- indicator.setText(IdeBundle.message("progress.indexing.updating"));
- if (count > 0) {
- updateRunner.processFiles(indicator, true);
- }
- updateRunner.updatingDone();
- }
- catch (ProcessCanceledException ignored) {
- }
- catch (Throwable unexpected) {
- LOG.error(unexpected);
- }
- updateRunner = getNextUpdateRunner();
+ DumbModeTask queuedTask = myUpdatesQueue.pullFirst();
+ ProgressIndicatorEx indicator = myProgresses.get(queuedTask);
+ if (indicator.isCanceled()) {
+ Disposer.dispose(queuedTask);
+ continue;
}
+
+ startBackgroundProcess(queuedTask, indicator);
+ return;
}
+ }
+ });
+ }
- @Nullable
- private CacheUpdateRunner getNextUpdateRunner() {
- final BlockingQueue<CacheUpdateRunner> actionQueue = new LinkedBlockingQueue<CacheUpdateRunner>();
- UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() {
- @Override
- public void run() {
- IndexUpdateRunnable nextRunnable = getNextUpdateFromQueue();
- try {
- actionQueue.offer(nextRunnable == null ? NULL_ACTION : nextRunnable.myAction);
- }
- finally {
- if (nextRunnable == null) {
- updateFinished();
- }
- }
- }
- });
-
- // try to obtain the next action or terminate if no actions left
- while (!myProject.isDisposed()) {
- try {
- CacheUpdateRunner ref = actionQueue.poll(500L, TimeUnit.MILLISECONDS);
- if (ref != null) {
- return ref == NULL_ACTION ? null : ref;
- }
- }
- catch (InterruptedException e) {
- LOG.info(e);
- }
- }
- return null;
+ private class AppIconProgress extends ProgressIndicatorBase {
+ double lastFraction;
+
+ @Override
+ public void setFraction(final double fraction) {
+ if (fraction - lastFraction < 0.01d) return;
+ lastFraction = fraction;
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ AppIcon.getInstance().setProgress(myProject, "indexUpdate", AppIconScheme.Progress.INDEXING, fraction, true);
}
+ });
+ }
- @Nullable
- private IndexUpdateRunnable getNextUpdateFromQueue() {
- try {
- return myUpdatesQueue.isEmpty()? null : myUpdatesQueue.pullFirst();
- }
- catch (Throwable e) {
- LOG.info(e);
- return null;
+ @Override
+ public void finish(@NotNull TaskInfo task) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ AppIcon appIcon = AppIcon.getInstance();
+ if (appIcon.hideProgress(myProject, "indexUpdate")) {
+ appIcon.requestAttention(myProject, false);
+ appIcon.setOkBadge(myProject, true);
}
}
});
}
}
-
}