ensure background indexing thread finished before VFS and index disposal (IDEA-72712)

This commit is contained in:
Eugene Zhuravlev
2011-08-02 15:45:37 +02:00
parent c782f85025
commit 42350338de
12 changed files with 49 additions and 77 deletions
@@ -334,7 +334,7 @@ public abstract class AbstractFileIndex<IndexEntry extends FileIndexEntry> imple
myFileTypesToRefresh = fileTypesToRefresh;
}
public VirtualFile[] queryNeededFiles() {
public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) {
return AbstractFileIndex.this.queryNeededFiles(myIncludeChangedFiles, myFileTypesToRefresh);
}
@@ -19,6 +19,7 @@ package com.intellij.util.fileIndex;
import com.intellij.ide.caches.CacheUpdater;
import com.intellij.ide.caches.FileContent;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.vfs.*;
@@ -70,7 +71,7 @@ public class FileIndexRefreshCacheUpdater extends VirtualFileAdapter implements
return 0;
}
public VirtualFile[] queryNeededFiles() {
public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) {
return VfsUtil.toVirtualFileArray(myChangedFiles);
}
@@ -1937,7 +1937,7 @@ public class FileBasedIndex implements ApplicationComponent {
}
}
public static void iterateIndexableFiles(final ContentIterator processor, Project project) {
public static void iterateIndexableFiles(final ContentIterator processor, Project project, ProgressIndicator indicator) {
if (project.isDisposed()) {
return;
}
@@ -1948,7 +1948,6 @@ public class FileBasedIndex implements ApplicationComponent {
if (project.isDisposed()) {
return;
}
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
Set<VirtualFile> visitedRoots = new HashSet<VirtualFile>();
for (IndexedRootsProvider provider : Extensions.getExtensions(IndexedRootsProvider.EP_NAME)) {
@@ -1999,6 +1998,7 @@ public class FileBasedIndex implements ApplicationComponent {
private static void iterateRecursively(@Nullable final VirtualFile root, final ContentIterator processor, ProgressIndicator indicator) {
if (root != null) {
if (indicator != null) {
indicator.checkCanceled();
indicator.setText2(root.getPresentableUrl());
}
@@ -2011,7 +2011,8 @@ public class FileBasedIndex implements ApplicationComponent {
processor.processFile(file);
}
}
} else {
}
else {
processor.processFile(root);
}
}
@@ -25,6 +25,7 @@ import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.file.exclude.ProjectFileExclusionManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
@@ -105,7 +106,7 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple
return myIndex.getNumberOfPendingInvalidations();
}
public VirtualFile[] queryNeededFiles() {
public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) {
Collection<VirtualFile> files = myIndex.getFilesToUpdate(myProject);
return VfsUtil.toVirtualFileArray(files);
}
@@ -19,6 +19,7 @@ package com.intellij.util.indexing;
import com.intellij.ide.caches.CacheUpdater;
import com.intellij.ide.caches.FileContent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CollectingContentIterator;
import com.intellij.openapi.vfs.VfsUtil;
@@ -45,10 +46,10 @@ public class UnindexedFilesUpdater implements CacheUpdater {
return myIndex.getNumberOfPendingInvalidations();
}
public VirtualFile[] queryNeededFiles() {
public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) {
CollectingContentIterator finder = myIndex.createContentIterator();
long l = System.currentTimeMillis();
FileBasedIndex.iterateIndexableFiles(finder, myProject);
FileBasedIndex.iterateIndexableFiles(finder, myProject, indicator);
LOG.info("Indexable files iterated in " + (System.currentTimeMillis() - l) + " ms");
List<VirtualFile> files = finder.getFiles();
LOG.info("Unindexed files update started: " + files.size() + " files to update");
@@ -16,12 +16,13 @@
package com.intellij.ide.caches;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.vfs.VirtualFile;
public interface CacheUpdater {
int getNumberOfPendingUpdateJobs();
VirtualFile[] queryNeededFiles();
VirtualFile[] queryNeededFiles(ProgressIndicator indicator);
void processFile(FileContent fileContent);
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbServiceImpl;
import com.intellij.openapi.project.Project;
@@ -48,7 +49,7 @@ public class ToggleDumbModeAction extends AnAction implements DumbAware {
return 0;
}
public VirtualFile[] queryNeededFiles() {
public VirtualFile[] queryNeededFiles(ProgressIndicator indicator) {
while (myDumb) {
try {
Thread.sleep(100);
@@ -544,6 +544,9 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
public void dispose() {
fireApplicationExiting();
ShutDownTracker.getInstance().ensureStopperThreadsFinished();
disposeComponents();
ourThreadExecutorsService.shutdownNow();
@@ -20,29 +20,22 @@ import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.progress.*;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.progress.util.SmoothProgressAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.psi.PsiLock;
import com.intellij.ui.SystemNotifications;
import com.intellij.util.containers.SortedList;
import gnu.trove.THashMap;
import org.jetbrains.annotations.*;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class ProgressManagerImpl extends ProgressManager implements Disposable{
@@ -57,7 +50,6 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable{
@NonNls private static final String NAME = "Progress Cancel Checker";
private static final boolean DISABLED = Comparing.equal(System.getProperty(PROCESS_CANCELED_EXCEPTION), "disabled");
private static final Map<String, Long> myWastedTime = new THashMap<String, Long>();
private volatile boolean enabled = true;
public ProgressManagerImpl(Application application) {
@@ -274,7 +266,6 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable{
else {
task.onCancel();
}
moreTimeWasted(time, task);
return result;
}
@@ -362,7 +353,6 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable{
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
task.onCancel();
moreTimeWasted(time, task);
}
}, ModalityState.NON_MODAL);
}
@@ -377,7 +367,6 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable{
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
task.onSuccess();
moreTimeWasted(time, task);
}
}, ModalityState.NON_MODAL);
}
@@ -395,40 +384,6 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable{
}
}
private static void moreTimeWasted(long time, Task timeEater) {
if (!ApplicationManagerEx.getApplicationEx().isInternal()) return;
synchronized (myWastedTime) {
String title = timeEater.getTitle();
Long total = myWastedTime.get(title);
myWastedTime.put(title, total == null ? time : total + time);
}
}
public static long getWastedTime() {
synchronized (myWastedTime) {
long result = 0;
for (Map.Entry<String, Long> each : myWastedTime.entrySet()) {
result += each.getValue();
}
return result;
}
}
public static List<Pair<String, Long>> getTimeWasters() {
synchronized (myWastedTime) {
SortedList<Pair<String, Long>> result = new SortedList<Pair<String, Long>>(new Comparator<Pair<String, Long>>() {
public int compare(Pair<String, Long> o1, Pair<String, Long> o2) {
return o2.second.compareTo(o1.second);
}
});
for (Map.Entry<String, Long> each : myWastedTime.entrySet()) {
result.add(Pair.create(each.getKey(), each.getValue()));
}
return result;
}
}
public void run(@NotNull final Task task) {
if (task.isHeadless()) {
new TaskRunnable(task, new EmptyProgressIndicator()).run();
@@ -48,7 +48,7 @@ public class CacheUpdateSession {
indicator.checkCanceled();
try {
jobsCount += each.getNumberOfPendingUpdateJobs();
List<VirtualFile> updaterFiles = Arrays.asList(each.queryNeededFiles());
List<VirtualFile> updaterFiles = Arrays.asList(each.queryNeededFiles(indicator));
processedUpdaters.add(each);
myFilesToUpdate.addAll(updaterFiles);
myUpdatersWithFiles.add(Pair.create(each, (Collection<VirtualFile>)new THashSet<VirtualFile>(updaterFiles)));
@@ -26,6 +26,7 @@ import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.BalloonHandler;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.wm.AppIconScheme;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
@@ -293,7 +294,7 @@ public class DumbServiceImpl extends DumbService {
@Override
public void finish(@NotNull TaskInfo task) {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
AppIcon appIcon = AppIcon.getInstance();
if (appIcon.hideProgress("indexUpdate")) {
@@ -327,11 +328,15 @@ public class DumbServiceImpl extends DumbService {
}
});
final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance();
final Thread self = Thread.currentThread();
try {
HeavyProcessLatch.INSTANCE.processStarted();
shutdownTracker.registerStopperThread(self);
runAction(proxy, myAction);
}
finally {
shutdownTracker.unregisterStopperThread(self);
HeavyProcessLatch.INSTANCE.processFinished();
}
}
@@ -52,26 +52,8 @@ public class ShutDownTracker implements Runnable {
public void run() {
myIsShutdownHookRunning = true;
Thread[] threads = getStopperThreads();
while (threads.length > 0) {
Thread thread = threads[0];
if (!thread.isAlive()) {
if (isRegistered(thread)) {
LOG.error("Thread '" + thread.getName() + "' did not unregister itself from ShutDownTracker.");
unregisterStopperThread(thread);
}
}
else {
try {
thread.join(100);
}
catch (InterruptedException ignored) {
}
}
threads = getStopperThreads();
}
ensureStopperThreadsFinished();
for (Runnable task = removeLast(myShutdownTasks); task != null; task = removeLast(myShutdownTasks)) {
// task can change myShutdownTasks
try {
@@ -92,6 +74,27 @@ public class ShutDownTracker implements Runnable {
}
}
public final void ensureStopperThreadsFinished() {
Thread[] threads = getStopperThreads();
while (threads.length > 0) {
Thread thread = threads[0];
if (!thread.isAlive()) {
if (isRegistered(thread)) {
LOG.error("Thread '" + thread.getName() + "' did not unregister itself from ShutDownTracker.");
unregisterStopperThread(thread);
}
}
else {
try {
thread.join(100);
}
catch (InterruptedException ignored) {
}
}
threads = getStopperThreads();
}
}
private synchronized boolean isRegistered(@NotNull Thread thread) {
return myThreads.contains(thread);
}