mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
restart indexing on root change, cancel on project disposing (IDEA-96277, IDEA-115651, some "already disposed" exceptions)
This commit is contained in:
@@ -15,14 +15,18 @@
|
||||
*/
|
||||
package com.intellij.openapi.project;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class DumbModeTask {
|
||||
public abstract class DumbModeTask implements Disposable {
|
||||
|
||||
public abstract void performInDumbMode(@NotNull ProgressIndicator indicator);
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,9 @@ public abstract class DumbService {
|
||||
return new ArrayList<T>(collection);
|
||||
}
|
||||
|
||||
public abstract void queueTask(DumbModeTask task);
|
||||
public abstract void queueTask(@NotNull DumbModeTask task);
|
||||
|
||||
public abstract void cancelTask(@NotNull DumbModeTask task);
|
||||
|
||||
public abstract JComponent wrapGently(@NotNull JComponent dumbUnawareContent, @NotNull Disposable parentDisposable);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.project.DumbModeTask;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -50,10 +51,14 @@ public class MockDumbService extends DumbService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueTask(DumbModeTask task) {
|
||||
public void queueTask(@NotNull DumbModeTask task) {
|
||||
task.performInDumbMode(new EmptyProgressIndicator());
|
||||
Disposer.dispose(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(@NotNull DumbModeTask task) { }
|
||||
|
||||
@Override
|
||||
public JComponent wrapGently(@NotNull JComponent dumbUnawareContent, @NotNull Disposable parentDisposable) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
+10
-3
@@ -164,14 +164,21 @@ public class PushedFilePropertiesUpdater {
|
||||
});
|
||||
}
|
||||
|
||||
private void queueTask(Runnable task) {
|
||||
myTasks.offer(task);
|
||||
DumbService.getInstance(myProject).queueTask(new DumbModeTask() {
|
||||
private void queueTask(Runnable action) {
|
||||
myTasks.offer(action);
|
||||
final DumbModeTask task = new DumbModeTask() {
|
||||
@Override
|
||||
public void performInDumbMode(@NotNull ProgressIndicator indicator) {
|
||||
performPushTasks();
|
||||
}
|
||||
};
|
||||
myProject.getMessageBus().connect(task).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
|
||||
@Override
|
||||
public void rootsChanged(ModuleRootEvent event) {
|
||||
DumbService.getInstance(myProject).cancelTask(task);
|
||||
}
|
||||
});
|
||||
DumbService.getInstance(myProject).queueTask(task);
|
||||
}
|
||||
|
||||
private void performPushTasks() {
|
||||
|
||||
+12
-2
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.caches.FileContent;
|
||||
import com.intellij.ide.startup.StartupManagerEx;
|
||||
@@ -29,6 +30,8 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.ModuleRootAdapter;
|
||||
import com.intellij.openapi.roots.ModuleRootEvent;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
|
||||
import com.intellij.openapi.roots.impl.ProjectRootManagerComponent;
|
||||
@@ -128,7 +131,7 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
// done mostly for tests. In real life this is noop, because the set was removed on project closing
|
||||
// done mostly for tests. In real life this is no-op, because the set was removed on project closing
|
||||
myIndex.removeIndexableSet(this);
|
||||
}
|
||||
|
||||
@@ -140,7 +143,7 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DumbModeTask() {
|
||||
final DumbModeTask task = new DumbModeTask() {
|
||||
@Override
|
||||
public void performInDumbMode(@NotNull ProgressIndicator indicator) {
|
||||
final Collection<VirtualFile> files = index.getFilesToUpdate(project);
|
||||
@@ -149,6 +152,13 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple
|
||||
reindexRefreshedFiles(indicator, files, project, index);
|
||||
}
|
||||
};
|
||||
project.getMessageBus().connect(task).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
|
||||
@Override
|
||||
public void rootsChanged(ModuleRootEvent event) {
|
||||
DumbService.getInstance(project).cancelTask(task);
|
||||
}
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
private static void reindexRefreshedFiles(ProgressIndicator indicator,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.caches.FileContent;
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
@@ -24,8 +25,11 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.CacheUpdateRunner;
|
||||
import com.intellij.openapi.project.DumbModeTask;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.CollectingContentIterator;
|
||||
import com.intellij.openapi.roots.ModuleRootAdapter;
|
||||
import com.intellij.openapi.roots.ModuleRootEvent;
|
||||
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -48,6 +52,12 @@ public class UnindexedFilesUpdater extends DumbModeTask {
|
||||
public UnindexedFilesUpdater(final Project project, boolean onStartup) {
|
||||
myProject = project;
|
||||
myOnStartup = onStartup;
|
||||
project.getMessageBus().connect(this).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
|
||||
@Override
|
||||
public void rootsChanged(ModuleRootEvent event) {
|
||||
DumbService.getInstance(project).cancelTask(UnindexedFilesUpdater.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateUnindexedFiles(ProgressIndicator indicator) {
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.intellij.openapi.project;
|
||||
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.caches.CacheUpdater;
|
||||
import com.intellij.ide.util.DelegatingProgressIndicator;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -28,6 +27,7 @@ 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.Ref;
|
||||
import com.intellij.openapi.util.ShutDownTracker;
|
||||
import com.intellij.openapi.wm.AppIconScheme;
|
||||
@@ -37,9 +37,9 @@ import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
|
||||
import com.intellij.openapi.wm.ex.StatusBarEx;
|
||||
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;
|
||||
@@ -48,28 +48,55 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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<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;
|
||||
|
||||
public DumbServiceImpl(Project project) {
|
||||
myProject = project;
|
||||
myPublisher = project.getMessageBus().syncPublisher(DUMB_MODE);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"})
|
||||
public static DumbServiceImpl getInstance(@NotNull Project project) {
|
||||
return (DumbServiceImpl)DumbService.getInstance(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueTask(final DumbModeTask task) {
|
||||
public void queueTask(@NotNull final DumbModeTask task) {
|
||||
scheduleCacheUpdate(task, true);
|
||||
}
|
||||
|
||||
public DumbServiceImpl(Project project, MessageBus bus) {
|
||||
myProject = project;
|
||||
myPublisher = bus.syncPublisher(DUMB_MODE);
|
||||
@Override
|
||||
public void cancelTask(@NotNull DumbModeTask task) {
|
||||
ProgressIndicatorEx indicator = myProgresses.get(task);
|
||||
if (indicator != null) {
|
||||
indicator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
@@ -134,6 +161,7 @@ public class DumbServiceImpl extends DumbService {
|
||||
if (indicator != null) {
|
||||
indicator.popState();
|
||||
}
|
||||
Disposer.dispose(task);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -145,6 +173,14 @@ public class DumbServiceImpl extends DumbService {
|
||||
return;
|
||||
}
|
||||
myUpdatesQueue.addLast(task);
|
||||
myProgresses.put(task, new ProgressIndicatorBase());
|
||||
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) {
|
||||
// always change dumb status inside write action.
|
||||
@@ -294,14 +330,12 @@ public class DumbServiceImpl extends DumbService {
|
||||
((ProgressIndicatorEx)indicator).addStateDelegate(new AppIconProgress());
|
||||
}
|
||||
|
||||
final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator);
|
||||
|
||||
final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance();
|
||||
final Thread self = Thread.currentThread();
|
||||
try {
|
||||
HeavyProcessLatch.INSTANCE.processStarted();
|
||||
shutdownTracker.registerStopperThread(self);
|
||||
runTasks(proxy);
|
||||
runTasks(indicator);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
LOG.error(e);
|
||||
@@ -313,16 +347,26 @@ public class DumbServiceImpl extends DumbService {
|
||||
}
|
||||
}
|
||||
|
||||
private void runTasks(ProgressIndicator indicator) {
|
||||
private void runTasks(ProgressIndicator visibleIndicator) {
|
||||
DumbModeTask prevTask = null;
|
||||
while (true) {
|
||||
DumbModeTask task = getNextTask();
|
||||
DumbModeTask task = getNextTask(prevTask);
|
||||
if (task == null) break;
|
||||
|
||||
try {
|
||||
if (ApplicationManager.getApplication().isInternal()) LOG.info("Running dumb mode task: " + task);
|
||||
|
||||
final ProgressIndicatorEx indicator = myProgresses.get(task);
|
||||
assert indicator != null;
|
||||
indicator.checkCanceled();
|
||||
|
||||
if (visibleIndicator instanceof ProgressIndicatorEx) {
|
||||
indicator.addStateDelegate((ProgressIndicatorEx)visibleIndicator);
|
||||
}
|
||||
|
||||
indicator.setIndeterminate(true);
|
||||
indicator.setText(IdeBundle.message("progress.indexing.scanning"));
|
||||
|
||||
task.performInDumbMode(indicator);
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
@@ -330,6 +374,7 @@ public class DumbServiceImpl extends DumbService {
|
||||
catch (Throwable unexpected) {
|
||||
LOG.error(unexpected);
|
||||
}
|
||||
prevTask = task;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,16 +382,30 @@ public class DumbServiceImpl extends DumbService {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DumbModeTask getNextTask() {
|
||||
private DumbModeTask getNextTask(@Nullable final DumbModeTask prevTask) {
|
||||
final Ref<DumbModeTask> nextTask = Ref.create();
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myProject.isDisposed()) return;
|
||||
if (myUpdatesQueue.isEmpty()) {
|
||||
updateFinished();
|
||||
} else {
|
||||
nextTask.set(myUpdatesQueue.pullFirst());
|
||||
if (prevTask != null) {
|
||||
Disposer.dispose(prevTask);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (myUpdatesQueue.isEmpty()) {
|
||||
updateFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
DumbModeTask queuedTask = myUpdatesQueue.pullFirst();
|
||||
if (myProgresses.get(queuedTask).isCanceled()) {
|
||||
Disposer.dispose(queuedTask);
|
||||
continue;
|
||||
}
|
||||
|
||||
nextTask.set(queuedTask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user