optimization: do not rebuild RootIndex when roots-unrelated directories changed

This commit is contained in:
Alexey Kudravtsev
2019-01-18 14:54:19 +03:00
parent 66c9b82c5f
commit aeb696fd59
4 changed files with 52 additions and 3 deletions
@@ -2,6 +2,7 @@
package com.intellij.java.openapi.roots.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
@@ -988,4 +989,24 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
assertEquals("Invalid package name for dir " + dir + ": " + packageName, packageName, actualName);
}
}
public void testUnrelatedDirectoriesCreationMustNotLeadToDirectoryIndexRebuildToImproveCheckoutPerformance() {
VirtualFile root = ModuleRootManager.getInstance(myModule).getContentRoots()[0];
WriteAction.run(()->ModuleRootModificationUtil.updateModel(myModule, model -> {
ContentEntry rootEntry = model.getContentEntries()[0];
for (int i=0;i<10_000;i++) {
VirtualFile src = createChildDirectory(root, "extsrc" + i);
rootEntry.addSourceFolder(src, false);
}
}));
ProjectFileIndex fileIndex = ProjectFileIndex.getInstance(getProject());
PlatformTestUtil.startPerformanceTest("dir creation must not lead to dirindex rebuild", 30_000, ()->{
for (int i=0; i<5_000; i++) {
VirtualFile xxx = createChildDirectory(root, "xxx");
assertFalse(fileIndex.isInSource(xxx));
delete(xxx);
}
}).assertTiming();
}
}
@@ -52,6 +52,11 @@ public class PackageDirectoryCache {
}
}
void clear() {
myNonExistentPackages.clear();
myDirectoriesByPackageNameCache.clear();
}
public void onLowMemory() {
myNonExistentPackages.clear();
}
@@ -86,7 +91,7 @@ public class PackageDirectoryCache {
}
for (VirtualFile file : myRootsByPackagePrefix.get(packageName)) {
if (file.isDirectory()) {
if (file.isDirectory() && file.isValid()) {
result.add(file);
}
}
@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeEvent;
import com.intellij.openapi.fileTypes.FileTypeListener;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
@@ -17,9 +18,12 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent;
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent;
import com.intellij.util.Query;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
@@ -64,6 +68,11 @@ public class DirectoryIndexImpl extends DirectoryIndex {
});
myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
@Override
public void beforeRootsChange(@NotNull ModuleRootEvent event) {
myRootIndex = null;
}
@Override
public void rootsChanged(@NotNull ModuleRootEvent event) {
myRootIndex = null;
@@ -75,7 +84,15 @@ public class DirectoryIndexImpl extends DirectoryIndex {
public void after(@NotNull List<? extends VFileEvent> events) {
RootIndex rootIndex = myRootIndex;
if (rootIndex != null && shouldResetOnEvents(events)) {
myRootIndex = null;
rootIndex.myPackageDirectoryCache.clear();
for (VFileEvent event : events) {
// TempFileSystem doesn't properly support virtual file pointers, so reset unconditionally
if (event.getFileSystem() instanceof TempFileSystem ||
isIgnoredFileCreated(event)) {
myRootIndex = null;
break;
}
}
}
}
});
@@ -91,6 +108,12 @@ public class DirectoryIndexImpl extends DirectoryIndex {
return false;
}
private static boolean isIgnoredFileCreated(@NotNull VFileEvent event) {
return event instanceof VFileMoveEvent && FileTypeRegistry.getInstance().isFileIgnored(((VFileMoveEvent)event).getNewParent()) ||
event instanceof VFilePropertyChangeEvent &&
((VFilePropertyChangeEvent)event).getPropertyName().equals(VirtualFile.PROP_NAME) &&
FileTypeRegistry.getInstance().isFileIgnored(((VFilePropertyChangeEvent)event).getFile());
}
private void dispatchPendingEvents() {
myConnection.deliverImmediately();
@@ -49,7 +49,7 @@ public class RootIndex {
private final Map<VirtualFile, DirectoryInfo> myRootInfos = ContainerUtil.newHashMap();
private final ConcurrentBitSet myNonInterestingIds = new ConcurrentBitSet();
@NotNull private final Project myProject;
private final PackageDirectoryCache myPackageDirectoryCache;
final PackageDirectoryCache myPackageDirectoryCache;
private OrderEntryGraph myOrderEntryGraph;
public RootIndex(@NotNull Project project) {