optimization: bulk add pointers to container

This commit is contained in:
Alexey Kudravtsev
2018-11-20 13:50:30 +03:00
parent 552c7927b5
commit 2ca41ddbf6
2 changed files with 57 additions and 32 deletions
@@ -35,15 +35,13 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ConcurrentList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.URLUtil;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import java.util.function.Predicate;
/**
@@ -189,15 +187,17 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme
assert !myDisposed;
dropCaches();
for (final VirtualFilePointer pointer : that.getList()) {
myList.addIfAbsent(duplicate(pointer));
}
for (VirtualFilePointer jarDirectory : ((VirtualFilePointerContainerImpl)that).myJarDirectories) {
myJarDirectories.add(duplicate(jarDirectory));
}
for (VirtualFilePointer jarRecursiveDirectory : ((VirtualFilePointerContainerImpl)that).myJarRecursiveDirectories) {
myJarRecursiveDirectories.add(duplicate(jarRecursiveDirectory));
Set<VirtualFilePointer> set = new THashSet<>(myList);
List<VirtualFilePointer> thatList = that.getList();
List<VirtualFilePointer> toAddList = new ArrayList<>(thatList.size());
for (final VirtualFilePointer pointer : thatList) {
if (!set.contains(pointer)) toAddList.add(duplicate(pointer));
}
myList.addAll(toAddList);
List<VirtualFilePointer> jarDups = ContainerUtil.map(((VirtualFilePointerContainerImpl)that).myJarDirectories, this::duplicate);
List<VirtualFilePointer> jarRecursiveDups = ContainerUtil.map(((VirtualFilePointerContainerImpl)that).myJarRecursiveDirectories, this::duplicate);
myJarDirectories.addAll(jarDups);
myJarRecursiveDirectories.addAll(jarRecursiveDups);
}
private void dropCaches() {
@@ -334,6 +334,7 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme
return myList.size()+myJarDirectories.size()+myJarRecursiveDirectories.size();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof VirtualFilePointerContainerImpl)) return false;
@@ -345,6 +346,7 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme
myJarRecursiveDirectories.equals(impl.myJarRecursiveDirectories);
}
@Override
public int hashCode() {
return myList.hashCode();
}
@@ -384,15 +386,11 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme
public VirtualFilePointerContainer clone(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener) {
assert !myDisposed;
VirtualFilePointerContainerImpl clone = (VirtualFilePointerContainerImpl)myVirtualFilePointerManager.createContainer(parent, listener);
for (VirtualFilePointer pointer : myList) {
clone.add(pointer.getUrl());
}
for (VirtualFilePointer jarDirectoryPtr : myJarDirectories) {
clone.addJarDirectory(jarDirectoryPtr.getUrl(), false);
}
for (VirtualFilePointer jarDirectoryPtr : myJarRecursiveDirectories) {
clone.addJarDirectory(jarDirectoryPtr.getUrl(), true);
}
List<VirtualFilePointer> toAdd = ContainerUtil.map(myList, p -> clone.create(p.getUrl()));
clone.myList.addAll(toAdd);
clone.addAllJarDirectories(ContainerUtil.map(myJarDirectories, VirtualFilePointer::getUrl), false);
clone.addAllJarDirectories(ContainerUtil.map(myJarRecursiveDirectories, VirtualFilePointer::getUrl), true);
return clone;
}
@@ -413,6 +411,23 @@ public class VirtualFilePointerContainerImpl extends TraceableDisposable impleme
dropCaches();
}
/** optimization: faster than calling {@link #addJarDirectory(String, boolean)} one by one */
public void addAllJarDirectories(@NotNull Collection<String> directoryUrls, boolean recursively) {
if (directoryUrls.isEmpty()) return;
Set<VirtualFilePointer> jars = new THashSet<>(recursively ? myJarRecursiveDirectories : myJarDirectories);
Set<VirtualFilePointer> list = new THashSet<>(myList);
List<VirtualFilePointer> toAddJars = new ArrayList<>(directoryUrls.size());
List<VirtualFilePointer> toAddList = new ArrayList<>(directoryUrls.size());
directoryUrls.forEach(url -> {
VirtualFilePointer pointer = myVirtualFilePointerManager.createDirectoryPointer(url, recursively, myParent, myListener);
if (!jars.contains(pointer)) toAddJars.add(pointer);
if (!list.contains(pointer)) toAddList.add(pointer);
});
(recursively ? myJarRecursiveDirectories : myJarDirectories).addAll(toAddJars);
myList.addAll(toAddList); // hack. jar directories need to be contained in class roots too (for externalization compatibility) but be ignored in getFiles()
dropCaches();
}
@Override
public boolean removeJarDirectory(@NotNull String directoryUrl) {
dropCaches();
@@ -27,6 +27,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.VirtualFileManagerAdapter;
import com.intellij.openapi.vfs.impl.VirtualFilePointerContainerImpl;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
@@ -44,6 +45,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collection;
import java.util.Set;
/**
@@ -184,26 +186,32 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
ApplicationManager.getApplication().assertIsDispatchThread();
if (myProject.isDefault()) return null;
final Set<String> recursive = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> flat = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> dirUrls = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> recursiveDirs = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> recursiveDirUrls = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> files = new THashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final String projectFilePath = myProject.getProjectFilePath();
final File projectDirFile = projectFilePath == null ? null : new File(projectFilePath).getParentFile();
if (projectDirFile != null && projectDirFile.getName().equals(Project.DIRECTORY_STORE_FOLDER)) {
recursive.add(projectDirFile.getAbsolutePath());
dirUrls.add(VfsUtilCore.pathToUrl(projectDirFile.getAbsolutePath()));
}
else {
flat.add(projectFilePath);
files.add(projectFilePath);
// may be not existing yet
ContainerUtil.addIfNotNull(flat, ProjectKt.getStateStore(myProject).getWorkspaceFilePath());
ContainerUtil.addIfNotNull(files, ProjectKt.getStateStore(myProject).getWorkspaceFilePath());
}
for (AdditionalLibraryRootsProvider extension : AdditionalLibraryRootsProvider.EP_NAME.getExtensions()) {
recursive.addAll(ContainerUtil.map(extension.getRootsToWatch(myProject), VirtualFile::getPath));
Collection<VirtualFile> toWatch = extension.getRootsToWatch(myProject);
recursiveDirs.addAll(ContainerUtil.map(toWatch, VirtualFile::getPath));
recursiveDirUrls.addAll(ContainerUtil.map(toWatch, VirtualFile::getUrl));
}
for (WatchedRootsProvider extension : WatchedRootsProvider.EP_NAME.getExtensions(myProject)) {
recursive.addAll(extension.getRootsToWatch());
Set<String> toWatch = extension.getRootsToWatch();
recursiveDirs.addAll(toWatch);
recursiveDirUrls.addAll(ContainerUtil.map(toWatch, p->VfsUtilCore.pathToUrl(FileUtil.toSystemIndependentName(p))));
}
Disposable oldDisposable = myRootPointersDisposable;
@@ -211,14 +219,16 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
Disposer.register(this, myRootPointersDisposable);
// create container with these urls with the sole purpose to get events to getRootsValidityChangedListener() when these roots change
VirtualFilePointerContainer container = VirtualFilePointerManager.getInstance().createContainer(myRootPointersDisposable, getRootsValidityChangedListener());
recursive.forEach(path -> container.addJarDirectory(VfsUtilCore.pathToUrl(path), true));
flat.forEach(path -> container.add(VfsUtilCore.pathToUrl(path)));
((VirtualFilePointerContainerImpl)container).addAllJarDirectories(recursiveDirUrls, true);
((VirtualFilePointerContainerImpl)container).addAllJarDirectories(dirUrls, false);
files.forEach(path -> container.add(VfsUtilCore.pathToUrl(path)));
Disposer.dispose(oldDisposable); // dispose after the re-creating container to keep virtual file pointers from disposing and re-creating back
// module roots already fire validity change events
addRootsFromModulesTo(recursive, flat);
return Pair.create(recursive, flat);
addRootsFromModulesTo(recursiveDirs, files);
return Pair.create(recursiveDirs, files);
}
private void addRootsFromModulesTo(@NotNull Set<? super String> recursive, @NotNull Set<? super String> flat) {