[platform] scheduling initial VFS refresh once from a b/g thread (IDEA-218043)

GitOrigin-RevId: ba960134e3138d8686ecabbbd971edc0531d20a2
This commit is contained in:
Roman Shevchenko
2019-08-22 01:50:10 +03:00
committed by intellij-monorepo-bot
parent fa1cd9c489
commit 3d44cb6513
3 changed files with 30 additions and 90 deletions
@@ -1,24 +1,10 @@
/*
* Copyright 2000-2016 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;
import com.intellij.ProjectTopics;
import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.startup.impl.StartupManagerImpl;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
@@ -27,12 +13,16 @@ 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.project.impl.ProjectLifecycleListener;
import com.intellij.openapi.roots.CollectingContentIterator;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -45,12 +35,10 @@ public class UnindexedFilesUpdater extends DumbModeTask {
private final FileBasedIndexImpl myIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance();
private final Project myProject;
private final StartupManager myStartupManager;
private final PushedFilePropertiesUpdater myPusher;
public UnindexedFilesUpdater(final Project project) {
myProject = project;
myStartupManager = StartupManager.getInstance(myProject);
myPusher = PushedFilePropertiesUpdater.getInstance(myProject);
project.getMessageBus().connect(this).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
@Override
@@ -84,7 +72,7 @@ public class UnindexedFilesUpdater extends DumbModeTask {
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// full VFS refresh makes sense only after it's loaded, i.e. after scanning files to index is finished
((StartupManagerImpl)myStartupManager).scheduleInitialVfsRefresh();
scheduleInitialVfsRefresh();
}
if (files.isEmpty()) {
@@ -103,6 +91,28 @@ public class UnindexedFilesUpdater extends DumbModeTask {
if (trackResponsiveness) snapshot.logResponsivenessSinceCreation("Unindexed files update");
}
private void scheduleInitialVfsRefresh() {
ProjectRootManagerEx.getInstanceEx(myProject).markRootsForRefresh();
Application app = ApplicationManager.getApplication();
if (!app.isCommandLine()) {
long sessionId = VirtualFileManager.getInstance().asyncRefresh(null);
MessageBusConnection connection = app.getMessageBus().connect();
connection.subscribe(ProjectLifecycleListener.TOPIC, new ProjectLifecycleListener() {
@Override
public void afterProjectClosed(@NotNull Project project) {
if (project == myProject) {
RefreshQueue.getInstance().cancelSession(sessionId);
connection.disconnect();
}
}
});
}
else {
VirtualFileManager.getInstance().syncRefresh();
}
}
private void indexFiles(ProgressIndicator indicator, List<VirtualFile> files) {
CacheUpdateRunner.processFiles(indicator, files, myProject, content -> myIndex.indexFileContent(myProject, content));
}
@@ -26,22 +26,17 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
import com.intellij.openapi.project.DumbModeTask;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.DumbServiceImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectLifecycleListener;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.impl.local.FileWatcher;
import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.project.ProjectKt;
import com.intellij.ui.GuiUtils;
import com.intellij.util.PathUtil;
@@ -49,7 +44,6 @@ import com.intellij.util.SmartList;
import com.intellij.util.TimeoutUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.io.storage.HeavyProcessLatch;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -79,7 +73,6 @@ public class StartupManagerImpl extends StartupManagerEx implements Disposable {
private volatile boolean myStartupActivitiesPassed;
private final Project myProject;
private boolean myInitialRefreshScheduled;
private ScheduledFuture<?> myBackgroundPostStartupScheduledFuture;
public StartupManagerImpl(@NotNull Project project) {
@@ -316,33 +309,6 @@ public class StartupManagerImpl extends StartupManagerEx implements Disposable {
}
}
public void scheduleInitialVfsRefresh() {
GuiUtils.invokeLaterIfNeeded(() -> {
if (myProject.isDisposed() || myInitialRefreshScheduled) return;
myInitialRefreshScheduled = true;
ProjectRootManagerEx.getInstanceEx(myProject).markRootsForRefresh();
Application app = ApplicationManager.getApplication();
if (!app.isCommandLine()) {
long sessionId = VirtualFileManager.getInstance().asyncRefresh(null);
MessageBusConnection connection = app.getMessageBus().connect();
connection.subscribe(ProjectLifecycleListener.TOPIC, new ProjectLifecycleListener() {
@Override
public void afterProjectClosed(@NotNull Project project) {
if (project == myProject) {
RefreshQueue.getInstance().cancelSession(sessionId);
connection.disconnect();
}
}
});
}
else {
VirtualFileManager.getInstance().syncRefresh();
}
}, ModalityState.defaultModalityState());
}
private void checkFsSanity() {
try {
String path = myProject.getProjectFilePath();
@@ -418,36 +384,6 @@ public class StartupManagerImpl extends StartupManagerEx implements Disposable {
});
}
public void startCacheUpdate() {
if (myProject.isDisposed()) return;
try {
DumbServiceImpl dumbService = DumbServiceImpl.getInstance(myProject);
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// pre-startup activities have registered dumb tasks that load VFS (scanning files to index)
// only after these tasks pass does VFS refresh make sense
dumbService.queueTask(new DumbModeTask() {
@Override
public void performInDumbMode(@NotNull ProgressIndicator indicator) {
scheduleInitialVfsRefresh();
}
@Override
public String toString() {
return "initial refresh";
}
});
}
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
LOG.error(e);
}
}
private void runActivities(@NotNull Deque<? extends Runnable> activities, @NotNull String phaseName) {
Activity activity = StartUpMeasurer.start(phaseName);
Runnable runnable;
@@ -420,12 +420,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
StartupManagerImpl startupManager = (StartupManagerImpl)StartupManager.getInstance(project);
startupManager.runStartupActivities();
// Startup activities (e.g. the one in FileBasedIndexProjectHandler) have scheduled dumb mode to begin "later"
// Now we schedule-and-wait to the same event queue to guarantee that the dumb mode really begins now:
// Post-startup activities should not ever see unindexed and at the same time non-dumb state
TransactionGuard.getInstance().submitTransactionAndWait(startupManager::startCacheUpdate);
startupManager.runPostStartupActivitiesFromExtensions();
GuiUtils.invokeLaterIfNeeded(() -> {