more efficient use of indices in stub hierarchy

This commit is contained in:
peter
2016-06-24 14:57:56 +02:00
parent 74276d773a
commit 95b3d482d9
7 changed files with 92 additions and 63 deletions
@@ -19,13 +19,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.EverythingGlobalScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubsHierarchy.HierarchyService;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
@@ -33,17 +31,18 @@ import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.CachedValueBase;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileBasedIndexImpl;
import org.jetbrains.annotations.NotNull;
import java.util.BitSet;
public class HierarchyServiceImpl extends HierarchyService {
private static final SingleClassHierarchy EMPTY_HIERARCHY = new SingleClassHierarchy(Symbol.ClassSymbol.EMPTY_ARRAY);
private final Project myProject;
private final ProjectFileIndex myFileIndex;
private final CachedValue<SingleClassHierarchy> myHierarchy;
public HierarchyServiceImpl(Project project) {
myProject = project;
myFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
myHierarchy = CachedValuesManager.getManager(project).createCachedValue(
() -> CachedValueProvider.Result.create(buildHierarchy(), PsiModificationTracker.MODIFICATION_COUNT),
false);
@@ -69,38 +68,56 @@ public class HierarchyServiceImpl extends HierarchyService {
private SingleClassHierarchy buildHierarchy() {
Symbols symbols = new Symbols();
StubEnter stubEnter = new StubEnter(symbols);
IdSets idSets = IdSets.getIdSets(myProject);
loadUnits(false, symbols.myNameEnvironment, stubEnter);
loadUnits(idSets.libraryFiles, StubHierarchyIndex.BINARY_FILES, symbols.myNameEnvironment, stubEnter);
stubEnter.connect1();
loadUnits(true, symbols.myNameEnvironment, stubEnter);
loadUnits(idSets.sourceFiles, StubHierarchyIndex.SOURCE_FILES, symbols.myNameEnvironment, stubEnter);
stubEnter.connect2();
return symbols.createHierarchy();
}
private void loadUnits(boolean sourceMode, NameEnvironment names, StubEnter stubEnter) {
GlobalSearchScope scope = new DelegatingGlobalSearchScope(new EverythingGlobalScope(myProject)) {
@Override
public boolean contains(@NotNull VirtualFile file) {
return sourceMode ? myFileIndex.isInSourceContent(file) : myFileIndex.isInLibraryClasses(file);
}
};
private void loadUnits(BitSet files, int indexKey, NameEnvironment names, StubEnter stubEnter) {
ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
FileBasedIndex index = FileBasedIndex.getInstance();
for (String packageName : index.getAllKeys(StubHierarchyIndex.INDEX_ID, myProject)) {
QualifiedName pkg = StringUtil.isEmpty(packageName) ? null : names.fromString(packageName, true);
index.processValues(StubHierarchyIndex.INDEX_ID, packageName, null, new FileBasedIndex.ValueProcessor<IndexTree.Unit>() {
int count = 0;
@Override
public boolean process(VirtualFile file, IndexTree.Unit unit) {
if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
stubEnter.unitEnter(Translator.internNames(names, unit, ((VirtualFileWithId)file).getId(), pkg));
return true;
FileBasedIndexImpl index = (FileBasedIndexImpl)FileBasedIndex.getInstance();
index.processAllValues(StubHierarchyIndex.INDEX_ID, indexKey, myProject, new FileBasedIndexImpl.IdValueProcessor<IndexTree.Unit>() {
int count = 0;
@Override
public boolean process(int fileId, IndexTree.Unit unit) {
if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
if (files.get(fileId)) {
QualifiedName pkg = StringUtil.isEmpty(unit.myPackageId) ? null : names.fromString(unit.myPackageId, true);
stubEnter.unitEnter(Translator.internNames(names, unit, fileId, pkg));
}
}, scope);
}
return true;
}
});
}
private static class IdSets {
final BitSet sourceFiles = new BitSet();
final BitSet libraryFiles = new BitSet();
static IdSets getIdSets(@NotNull Project project) {
return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
IdSets answer = new IdSets();
ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
FileBasedIndex.getInstance().iterateIndexableFiles(file -> {
if (!file.isDirectory() && file instanceof VirtualFileWithId) {
if (index.isInSourceContent(file)) {
answer.sourceFiles.set(((VirtualFileWithId) file).getId());
}
else if (index.isInLibraryClasses(file)) {
answer.libraryFiles.set(((VirtualFileWithId) file).getId());
}
}
return true;
}, project, ProgressIndicatorProvider.getGlobalProgressIndicator());
return CachedValueProvider.Result.create(answer, ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS);
});
}
}
}
@@ -18,7 +18,6 @@ package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiNameHelper;
@@ -39,7 +38,10 @@ import com.intellij.util.indexing.FileContent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class JavaStubIndexer extends StubHierarchyIndexer {
@@ -61,7 +63,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
@Nullable
@Override
public List<Pair<String, Unit>> indexFile(@NotNull FileContent content) {
public Unit indexFile(@NotNull FileContent content) {
Stub stubTree = StubTreeBuilder.buildStubTree(content);
if (!(stubTree instanceof PsiJavaFileStub)) return null;
@@ -87,7 +89,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]);
Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]);
byte type = javaFileStub.isCompiled() ? IndexTree.BYTECODE : IndexTree.JAVA;
return Collections.singletonList(Pair.create(javaFileStub.getPackageName(), new Unit(type, imports, classes)));
return new Unit(javaFileStub.getPackageName(), type, imports, classes);
}
@Nullable
@@ -18,47 +18,42 @@ package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor;
import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
/**
* @author peter
*/
public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTree.Unit> implements PsiDependentIndex {
static final ID<String, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
public class StubHierarchyIndex extends FileBasedIndexExtension<Integer, IndexTree.Unit> implements PsiDependentIndex {
public static final int BINARY_FILES = 0;
public static final int SOURCE_FILES = 1;
static final ID<Integer, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
private static final StubHierarchyIndexer[] ourIndexers = StubHierarchyIndexer.EP_NAME.getExtensions();
@NotNull
@Override
public ID<String, IndexTree.Unit> getName() {
public ID<Integer, IndexTree.Unit> getName() {
return INDEX_ID;
}
@NotNull
@Override
public DataIndexer<String, IndexTree.Unit, FileContent> getIndexer() {
public DataIndexer<Integer, IndexTree.Unit, FileContent> getIndexer() {
return inputData -> {
for (StubHierarchyIndexer indexer : ourIndexers) {
List<Pair<String, IndexTree.Unit>> pairs = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
if (pairs != null && !pairs.isEmpty()) {
Map<String, IndexTree.Unit> answer = new HashMap<>();
for (Pair<String, IndexTree.Unit> entry : pairs) {
if (entry.second.myDecls.length > 0) {
answer.put(StringUtil.notNullize(entry.first), entry.second);
}
}
return answer;
IndexTree.Unit unit = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
if (unit != null && unit.myDecls.length > 0) {
return Collections.singletonMap(inputData.getFile().getFileType().isBinary() ? BINARY_FILES : SOURCE_FILES, unit);
}
}
return Collections.emptyMap();
@@ -67,8 +62,8 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
@NotNull
@Override
public KeyDescriptor<String> getKeyDescriptor() {
return EnumeratorStringDescriptor.INSTANCE;
public KeyDescriptor<Integer> getKeyDescriptor() {
return EnumeratorIntegerDescriptor.INSTANCE;
}
@NotNull
@@ -79,7 +74,7 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
@Override
public int getVersion() {
return IndexTree.STUB_HIERARCHY_ENABLED ? 2 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
return IndexTree.STUB_HIERARCHY_ENABLED ? 3 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
}
@NotNull