mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ensure background indexing thread finished before VFS and index disposal (IDEA-72712)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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();
|
||||
|
||||
-45
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user