mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
javac ast indices uses MapReduceIndex
This commit is contained in:
@@ -24,6 +24,8 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import com.intellij.util.indexing.StorageException;
|
||||
import com.intellij.util.indexing.ValueContainer;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -31,27 +33,25 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompilerIndices;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
class CompilerReferenceReader {
|
||||
private final static Logger LOG = Logger.getInstance(CompilerReferenceReader.class);
|
||||
|
||||
private final CompilerBackwardReferenceIndex myIndex;
|
||||
|
||||
private final Object myHierarchyLock = new Object(); //access to hierarchy & definition maps
|
||||
private final Object myReferenceLock = new Object(); //access to reference & file enumerator maps
|
||||
|
||||
private CompilerReferenceReader(File buildDir) throws IOException {
|
||||
myIndex = new CompilerBackwardReferenceIndex(buildDir);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
TIntHashSet findReferentFileIds(@NotNull LightRef ref, boolean checkBaseClassAmbiguity) {
|
||||
TIntHashSet findReferentFileIds(@NotNull LightRef ref, boolean checkBaseClassAmbiguity) throws StorageException {
|
||||
LightRef.LightClassHierarchyElementDef hierarchyElement = ref instanceof LightRef.LightClassHierarchyElementDef ?
|
||||
(LightRef.LightClassHierarchyElementDef)ref :
|
||||
((LightRef.LightMember)ref).getOwner();
|
||||
@@ -76,38 +76,22 @@ class CompilerReferenceReader {
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull GlobalSearchScope dirtyScope,
|
||||
@NotNull FileType fileType,
|
||||
@NotNull CompilerHierarchySearchType searchType) {
|
||||
Collection<CompilerBackwardReferenceIndex.LightDefinition> candidates;
|
||||
synchronized (myHierarchyLock) {
|
||||
candidates = myIndex.getBackwardHierarchyMap().get(searchElement);
|
||||
}
|
||||
if (candidates == null) return Collections.emptyMap();
|
||||
|
||||
@NotNull CompilerHierarchySearchType searchType) throws StorageException {
|
||||
GlobalSearchScope effectiveSearchScope = GlobalSearchScope.notScope(dirtyScope).intersectWith(searchScope);
|
||||
LanguageLightRefAdapter adapter = CompilerReferenceServiceImpl.findAdapterForFileType(fileType);
|
||||
LOG.assertTrue(adapter != null, "adapter is null for file type: " + fileType);
|
||||
Class<? extends LightRef> requiredLightRefClass = searchType.getRequiredClass(adapter);
|
||||
Map<VirtualFile, Object[]> candidatesPerFile;
|
||||
synchronized (myReferenceLock) {
|
||||
candidatesPerFile = candidates
|
||||
.stream()
|
||||
.filter(def -> requiredLightRefClass.isInstance(def.getRef()))
|
||||
.map(definition -> {
|
||||
final VirtualFile file = findFile(definition.getFileId());
|
||||
if (file != null && effectiveSearchScope.contains(file)) {
|
||||
return new Object() {
|
||||
final VirtualFile containingFile = file;
|
||||
final LightRef def = definition.getRef();
|
||||
};
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(groupingBy(x -> x.containingFile, mapping(x -> x.def, collectingAndThen(toList(), l -> searchType.convertToIds(l, myIndex.getByteSeqEum())))));
|
||||
}
|
||||
|
||||
Map<VirtualFile, Object[]> candidatesPerFile = new HashMap<>();
|
||||
myIndex.get(CompilerIndices.BACK_HIERARCHY).getData(searchElement).forEach((fileId, defs) -> {
|
||||
final List<LightRef> requiredCandidates = defs.stream().filter(requiredLightRefClass::isInstance).collect(toList());
|
||||
if (requiredCandidates.isEmpty()) return true;
|
||||
final VirtualFile file = findFile(fileId);
|
||||
if (file != null && effectiveSearchScope.contains(file)) {
|
||||
candidatesPerFile.put(file, searchType.convertToIds(defs, myIndex.getByteSeqEum()));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return candidatesPerFile.isEmpty() ? Collections.emptyMap() : candidatesPerFile;
|
||||
}
|
||||
|
||||
@@ -133,19 +117,18 @@ class CompilerReferenceReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void addUsages(LightRef usage, TIntHashSet sink) {
|
||||
final Collection<Integer> usageFiles;
|
||||
synchronized (myReferenceLock) {
|
||||
usageFiles = myIndex.getBackwardReferenceMap().get(usage);
|
||||
if (usageFiles != null) {
|
||||
for (int fileId : usageFiles) {
|
||||
final VirtualFile file = findFile(fileId);
|
||||
private void addUsages(LightRef usage, TIntHashSet sink) throws StorageException {
|
||||
myIndex.get(CompilerIndices.BACK_USAGES).getData(usage).forEach(
|
||||
new ValueContainer.ContainerAction<Void>() {
|
||||
@Override
|
||||
public boolean perform(int id, Void value) {
|
||||
final VirtualFile file = findFile(id);
|
||||
if (file != null) {
|
||||
sink.add(((VirtualFileWithId)file).getId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private VirtualFile findFile(int id) {
|
||||
@@ -160,38 +143,55 @@ class CompilerReferenceReader {
|
||||
}
|
||||
|
||||
@Nullable("return null if the class hierarchy contains ambiguous qualified names")
|
||||
private LightRef.NamedLightRef[] getWholeHierarchy(LightRef.LightClassHierarchyElementDef hierarchyElement, boolean checkBaseClassAmbiguity) {
|
||||
private LightRef.NamedLightRef[] getWholeHierarchy(LightRef.LightClassHierarchyElementDef hierarchyElement, boolean checkBaseClassAmbiguity)
|
||||
throws StorageException {
|
||||
Set<LightRef.NamedLightRef> result = new THashSet<>();
|
||||
Queue<LightRef.NamedLightRef> q = new Queue<>(10);
|
||||
q.addLast(hierarchyElement);
|
||||
synchronized (myHierarchyLock) {
|
||||
while (!q.isEmpty()) {
|
||||
LightRef.NamedLightRef curClass = q.pullFirst();
|
||||
if (result.add(curClass)) {
|
||||
if (checkBaseClassAmbiguity || curClass != hierarchyElement) {
|
||||
final Collection<Integer> definitionFiles = myIndex.getBackwardClassDefinitionMap().get(curClass);
|
||||
if (definitionFiles == null) {
|
||||
//diagnostic
|
||||
String baseHierarchyElement = getNameEnumerator().getName(hierarchyElement.getName());
|
||||
String curHierarchyElement = getNameEnumerator().getName(curClass.getName());
|
||||
LOG.error("Can't get definition files for :" + curHierarchyElement + " base class: " + baseHierarchyElement);
|
||||
}
|
||||
if (definitionFiles.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
while (!q.isEmpty()) {
|
||||
LightRef.NamedLightRef curClass = q.pullFirst();
|
||||
if (result.add(curClass)) {
|
||||
if (checkBaseClassAmbiguity || curClass != hierarchyElement) {
|
||||
DefCount count = getDefinitionCount(curClass);
|
||||
if (count == DefCount.NONE) {
|
||||
//diagnostic
|
||||
String baseHierarchyElement = getNameEnumerator().getName(hierarchyElement.getName());
|
||||
String curHierarchyElement = getNameEnumerator().getName(curClass.getName());
|
||||
LOG.error("Can't get definition files for :" + curHierarchyElement + " base class: " + baseHierarchyElement);
|
||||
}
|
||||
final Collection<CompilerBackwardReferenceIndex.LightDefinition> subClassDefs = myIndex.getBackwardHierarchyMap().get(curClass);
|
||||
if (subClassDefs != null) {
|
||||
for (CompilerBackwardReferenceIndex.LightDefinition subclass : subClassDefs) {
|
||||
final LightRef ref = subclass.getRef();
|
||||
if (ref instanceof LightRef.LightClassHierarchyElementDef) {
|
||||
q.addLast((LightRef.LightClassHierarchyElementDef) ref);
|
||||
}
|
||||
}
|
||||
if (count != DefCount.ONE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
myIndex.get(CompilerIndices.BACK_HIERARCHY).getData(curClass).forEach((id, children) -> {
|
||||
for (LightRef child : children) {
|
||||
q.addLast((LightRef.LightClassHierarchyElementDef) child);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
return result.toArray(new LightRef.NamedLightRef[result.size()]);
|
||||
}
|
||||
|
||||
private enum DefCount { NONE, ONE, MANY}
|
||||
@NotNull
|
||||
private DefCount getDefinitionCount(LightRef def) throws StorageException {
|
||||
DefCount[] result = new DefCount[]{DefCount.NONE};
|
||||
myIndex.get(CompilerIndices.BACK_CLASS_DEF).getData(def).forEach(new ValueContainer.ContainerAction<Void>() {
|
||||
@Override
|
||||
public boolean perform(int id, Void value) {
|
||||
if (result[0] == DefCount.NONE) {
|
||||
result[0] = DefCount.ONE;
|
||||
return true;
|
||||
}
|
||||
if (result[0] == DefCount.ONE) {
|
||||
result[0] = DefCount.MANY;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import com.intellij.util.indexing.StorageException;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -266,7 +267,12 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
myReadDataLock.lock();
|
||||
try {
|
||||
if (myReader == null) return null;
|
||||
return myReader.getDirectInheritors(searchElement, useScope, myDirtyModulesHolder.getDirtyScope(), searchFileType, searchType);
|
||||
try {
|
||||
return myReader.getDirectInheritors(searchElement, useScope, myDirtyModulesHolder.getDirtyScope(), searchFileType, searchType);
|
||||
}
|
||||
catch (StorageException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
myReadDataLock.unlock();
|
||||
}
|
||||
@@ -291,10 +297,15 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
if (myReader == null) return null;
|
||||
TIntHashSet referentFileIds = new TIntHashSet();
|
||||
for (LightRef ref : compilerElementInfo.searchElements) {
|
||||
final TIntHashSet referents = myReader.findReferentFileIds(ref, compilerElementInfo.place == ElementPlace.SRC);
|
||||
if (referents == null) return null;
|
||||
referentFileIds.addAll(referents.toArray());
|
||||
}
|
||||
try {
|
||||
final TIntHashSet referents = myReader.findReferentFileIds(ref, compilerElementInfo.place == ElementPlace.SRC);
|
||||
if (referents == null) return null;
|
||||
referentFileIds.addAll(referents.toArray());
|
||||
}
|
||||
catch (StorageException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return referentFileIds;
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -15,47 +15,65 @@
|
||||
*/
|
||||
package org.jetbrains.jps.backwardRefs;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class BackwardReferenceIndexUtil {
|
||||
static void registerFile(String filePath,
|
||||
Set<? extends JavacRef> refs,
|
||||
List<JavacDef> defs,
|
||||
BackwardReferenceIndexWriter writer) {
|
||||
final BackwardReferenceIndexWriter writer) {
|
||||
final int fileId = writer.enumeratePath(filePath);
|
||||
int funExprId = 0;
|
||||
|
||||
final List<LightRef> definitions = new ArrayList<LightRef>(defs.size());
|
||||
final Map<LightRef, Void> definitions = new HashMap<LightRef, Void>(defs.size());
|
||||
final Map<LightRef, Collection<LightRef>> backwardHierarchyMap = new HashMap<LightRef, Collection<LightRef>>();
|
||||
|
||||
for (JavacDef def : defs) {
|
||||
if (def instanceof JavacDef.JavacClassDef) {
|
||||
JavacRef.JavacClass sym = (JavacRef.JavacClass)def.getDefinedElement();
|
||||
final LightRef.JavaLightClassRef aClass = writer.asClassUsage(sym);
|
||||
definitions.add(aClass);
|
||||
definitions.put(aClass, null);
|
||||
|
||||
final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses();
|
||||
final LightRef.JavaLightClassRef[] lightSuperClasses = new LightRef.JavaLightClassRef[superClasses.length];
|
||||
for (int i = 0; i < superClasses.length; i++) {
|
||||
JavacRef superClass = superClasses[i];
|
||||
lightSuperClasses[i] = writer.asClassUsage(superClass);
|
||||
}
|
||||
for (JavacRef superClass : superClasses) {
|
||||
LightRef.JavaLightClassRef superClassRef = writer.asClassUsage(superClass);
|
||||
|
||||
writer.writeHierarchy(fileId, aClass, lightSuperClasses);
|
||||
Collection<LightRef> children = backwardHierarchyMap.get(superClassRef);
|
||||
if (children == null) {
|
||||
backwardHierarchyMap.put(superClassRef, children = new SmartList<LightRef>());
|
||||
}
|
||||
children.add(aClass);
|
||||
}
|
||||
}
|
||||
else if (def instanceof JavacDef.JavacFunExprDef) {
|
||||
final LightRef.JavaLightClassRef functionalType = writer.asClassUsage(def.getDefinedElement());
|
||||
int id = funExprId++;
|
||||
LightRef.JavaLightFunExprDef result = new LightRef.JavaLightFunExprDef(id);
|
||||
definitions.add(result);
|
||||
writer.writeHierarchy(fileId, result, functionalType);
|
||||
definitions.put(result, null);
|
||||
|
||||
ContainerUtil.getOrCreate(backwardHierarchyMap, functionalType, new Factory<Collection<LightRef>>() {
|
||||
@Override
|
||||
public Collection<LightRef> create() {
|
||||
return new SmartList<LightRef>();
|
||||
}
|
||||
}).add(result);
|
||||
}
|
||||
}
|
||||
|
||||
writer.writeClassDefinitions(fileId, definitions);
|
||||
writer.writeReferences(fileId, refs);
|
||||
Map<LightRef, Void> convertedRefs = new HashMap<LightRef, Void>(refs.size());
|
||||
for (JavacRef ref : refs) {
|
||||
LightRef key = writer.enumerateNames(ref);
|
||||
if (key != null) {
|
||||
convertedRefs.put(key, null);
|
||||
}
|
||||
}
|
||||
writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, convertedRefs, definitions));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
package org.jetbrains.jps.backwardRefs;
|
||||
|
||||
import com.intellij.openapi.util.LowMemoryWatcher;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.InvertedIndex;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
@@ -34,7 +32,6 @@ import org.jetbrains.jps.model.java.compiler.JavaCompilers;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.sun.tools.javac.code.Flags.PRIVATE;
|
||||
|
||||
@@ -44,24 +41,9 @@ public class BackwardReferenceIndexWriter {
|
||||
private static volatile BackwardReferenceIndexWriter ourInstance;
|
||||
|
||||
private final CompilerBackwardReferenceIndex myIndex;
|
||||
private final boolean myRebuild;
|
||||
private final LowMemoryWatcher myMemWatcher;
|
||||
private final Object myCloseLock = new Object();
|
||||
private boolean myClosed;
|
||||
|
||||
private BackwardReferenceIndexWriter(CompilerBackwardReferenceIndex index, boolean rebuild) {
|
||||
private BackwardReferenceIndexWriter(CompilerBackwardReferenceIndex index) {
|
||||
myIndex = index;
|
||||
myRebuild = rebuild;
|
||||
myMemWatcher = LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (myCloseLock) {
|
||||
if (!myClosed) {
|
||||
myIndex.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void closeIfNeed() {
|
||||
@@ -96,7 +78,7 @@ public class BackwardReferenceIndexWriter {
|
||||
}
|
||||
|
||||
if (CompilerBackwardReferenceIndex.exist(buildDir) || isRebuild) {
|
||||
ourInstance = new BackwardReferenceIndexWriter(new CompilerBackwardReferenceIndex(buildDir), isRebuild);
|
||||
ourInstance = new BackwardReferenceIndexWriter(new CompilerBackwardReferenceIndex(buildDir));
|
||||
}
|
||||
} else {
|
||||
CompilerBackwardReferenceIndex.removeIndexFiles(buildDir);
|
||||
@@ -111,99 +93,15 @@ public class BackwardReferenceIndexWriter {
|
||||
return new LightRef.JavaLightClassRef(id(aClass, myIndex.getByteSeqEum()));
|
||||
}
|
||||
|
||||
synchronized void processDeletedFiles(Collection<String> paths) {
|
||||
for (String path : paths) {
|
||||
final int deletedFileId = enumeratePath(new File(path).getPath());
|
||||
|
||||
//remove from reference maps
|
||||
final Collection<LightRef> refs = myIndex.getReferenceMap().get(deletedFileId);
|
||||
if (refs != null) {
|
||||
for (LightRef ref : refs) {
|
||||
myIndex.getBackwardReferenceMap().removeFrom(ref, deletedFileId);
|
||||
}
|
||||
}
|
||||
myIndex.getReferenceMap().remove(deletedFileId);
|
||||
|
||||
//remove from definition & hierarchy maps
|
||||
final Collection<LightRef> definedClasses = myIndex.getClassDefinitionMap().get(deletedFileId);
|
||||
removeClassesFromHierarchy(deletedFileId, definedClasses);
|
||||
myIndex.getClassDefinitionMap().remove(deletedFileId);
|
||||
void processDeletedFiles(Collection<String> files) {
|
||||
for (String file : files) {
|
||||
writeData(enumeratePath(file), null);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void writeClassDefinitions(int fileId, Collection<LightRef> classes) {
|
||||
if (myRebuild) {
|
||||
directlyWriteClassDefinitions(fileId, classes);
|
||||
} else {
|
||||
updateClassDefinitions(fileId, classes);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateClassDefinitions(int fileId, Collection<LightRef> classes) {
|
||||
final Collection<LightRef> oldDefs = myIndex.getClassDefinitionMap().get(fileId);
|
||||
final Collection<LightRef> oldDefsCopy = oldDefs == null ? null : new THashSet<LightRef>(oldDefs);
|
||||
|
||||
myIndex.getClassDefinitionMap().replace(fileId, classes);
|
||||
for (LightRef aClass : classes) {
|
||||
if (oldDefsCopy == null || !oldDefsCopy.remove(aClass)) {
|
||||
myIndex.getBackwardClassDefinitionMap().put(aClass, fileId);
|
||||
}
|
||||
}
|
||||
|
||||
removeClassesFromHierarchy(fileId, oldDefsCopy);
|
||||
}
|
||||
|
||||
private void directlyWriteClassDefinitions(int fileId, Collection<LightRef> classes) {
|
||||
myIndex.getClassDefinitionMap().put(fileId, classes);
|
||||
for (LightRef aClass : classes) {
|
||||
myIndex.getBackwardClassDefinitionMap().put(aClass, fileId);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void writeReferences(int fileId, Collection<? extends JavacRef> refs) {
|
||||
final ByteArrayEnumerator byteSeqEum = myIndex.getByteSeqEum();
|
||||
final Set<LightRef> usages = ContainerUtil.map2SetNotNull(refs, new Function<JavacRef, LightRef>() {
|
||||
@Override
|
||||
public LightRef fun(JavacRef ref) {
|
||||
return enumerateNames(ref, byteSeqEum);
|
||||
}
|
||||
});
|
||||
|
||||
if (myRebuild) {
|
||||
for (LightRef usage : usages) {
|
||||
myIndex.getBackwardReferenceMap().put(usage, fileId);
|
||||
myIndex.getReferenceMap().put(fileId, usage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateReferenceIndicesIncrementally(fileId, usages);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateReferenceIndicesIncrementally(int fileId, Collection<LightRef> usages) {
|
||||
final Collection<LightRef> rawOldUsages = myIndex.getReferenceMap().get(fileId);
|
||||
Collection<LightRef> oldUsages = rawOldUsages == null ? null : new THashSet<LightRef>(rawOldUsages);
|
||||
for (LightRef usage : usages) {
|
||||
if (oldUsages == null || !oldUsages.remove(usage)) {
|
||||
myIndex.getBackwardReferenceMap().put(usage, fileId);
|
||||
myIndex.getReferenceMap().put(fileId, usage);
|
||||
}
|
||||
}
|
||||
if (oldUsages != null && !oldUsages.isEmpty()) {
|
||||
myIndex.getReferenceMap().removeAll(fileId, oldUsages);
|
||||
for (LightRef usage : oldUsages) {
|
||||
myIndex.getBackwardReferenceMap().removeFrom(usage, fileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void writeHierarchy(int fileId, LightRef aClass, LightRef.JavaLightClassRef... supers) {
|
||||
CompilerBackwardReferenceIndex.LightDefinition def = new CompilerBackwardReferenceIndex.LightDefinition(aClass, fileId);
|
||||
if (myRebuild) {
|
||||
directlyWriteHierarchyIndices(def, supers);
|
||||
}
|
||||
else {
|
||||
updateHierarchyIndicesIncrementally(def, supers);
|
||||
void writeData(int id, CompiledFileData d) {
|
||||
for (InvertedIndex<?, ?, CompiledFileData> index : myIndex.getIndices()) {
|
||||
index.update(id, d).compute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,73 +115,12 @@ public class BackwardReferenceIndexWriter {
|
||||
}
|
||||
|
||||
private void close() {
|
||||
synchronized (myCloseLock) {
|
||||
myClosed = true;
|
||||
myMemWatcher.stop();
|
||||
myIndex.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void directlyWriteHierarchyIndices(CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) {
|
||||
for (LightRef.JavaLightClassRef superId : superIds) {
|
||||
myIndex.getBackwardHierarchyMap().put(superId, classId);
|
||||
myIndex.getHierarchyMap().put(classId, superId);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHierarchyIndicesIncrementally(final CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) {
|
||||
final Collection<LightRef> rawOldSupers = myIndex.getHierarchyMap().get(classId);
|
||||
Set<LightRef> oldSuperClasses;
|
||||
if (rawOldSupers == null) {
|
||||
oldSuperClasses = null;
|
||||
}
|
||||
else {
|
||||
if (superIds.length == rawOldSupers.size()) {
|
||||
boolean needUpdate = false;
|
||||
for (LightRef.JavaLightClassRef id : superIds) {
|
||||
if (!rawOldSupers.contains(id)) {
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!needUpdate) return;
|
||||
}
|
||||
oldSuperClasses = new THashSet<LightRef>(rawOldSupers);
|
||||
}
|
||||
for (LightRef.JavaLightClassRef superId: superIds) {
|
||||
if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) {
|
||||
myIndex.getBackwardHierarchyMap().put(superId, classId);
|
||||
myIndex.getHierarchyMap().put(classId, superId);
|
||||
}
|
||||
}
|
||||
if (oldSuperClasses != null && !oldSuperClasses.isEmpty()) {
|
||||
myIndex.getHierarchyMap().removeAll(classId, oldSuperClasses);
|
||||
for (LightRef anOldClass : oldSuperClasses) {
|
||||
myIndex.getBackwardHierarchyMap().removeFrom(anOldClass, classId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removeClassesFromHierarchy(int deletedFileId, Collection<LightRef> definedClasses) {
|
||||
if (definedClasses != null) {
|
||||
for (LightRef aClass : definedClasses) {
|
||||
myIndex.getBackwardClassDefinitionMap().removeFrom(aClass, deletedFileId);
|
||||
final CompilerBackwardReferenceIndex.LightDefinition def =
|
||||
new CompilerBackwardReferenceIndex.LightDefinition(aClass, deletedFileId);
|
||||
final Collection<LightRef> superClasses = myIndex.getHierarchyMap().get(def);
|
||||
if (superClasses != null) {
|
||||
for (LightRef superClass : superClasses) {
|
||||
myIndex.getBackwardHierarchyMap().removeFrom(superClass, def);
|
||||
}
|
||||
}
|
||||
myIndex.getHierarchyMap().remove(def);
|
||||
}
|
||||
}
|
||||
myIndex.close();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LightRef enumerateNames(JavacRef ref, ByteArrayEnumerator byteArrayEnumerator) {
|
||||
LightRef enumerateNames(JavacRef ref) {
|
||||
ByteArrayEnumerator byteArrayEnumerator = myIndex.getByteSeqEum();
|
||||
if (ref instanceof JavacRef.JavacClass) {
|
||||
if (!isPrivate(ref) && !((JavacRef.JavacClass)ref).isAnonymous()) {
|
||||
return new LightRef.JavaLightClassRef(id(ref, byteArrayEnumerator));
|
||||
|
||||
@@ -15,50 +15,53 @@
|
||||
*/
|
||||
package org.jetbrains.jps.backwardRefs;
|
||||
|
||||
import com.intellij.openapi.util.LowMemoryWatcher;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.indexing.impl.*;
|
||||
import com.intellij.util.io.*;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.CloseableMaplet;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.CollectionFactory;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.IntObjectPersistentMultiMaplet;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.ObjectObjectPersistentMultiMaplet;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
|
||||
import org.jetbrains.jps.backwardRefs.index.CompilerIndices;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class CompilerBackwardReferenceIndex {
|
||||
private static final int VERSION = 0;
|
||||
private final static String FILE_ENUM_TAB = "file.path.enum.tab";
|
||||
private final static String INCOMPLETE_FILES_TAB = "incomplete.files.tab";
|
||||
private final static String USAGES_TAB = "refs.tab";
|
||||
private final static String BACK_USAGES_TAB = "back.refs.tab";
|
||||
private final static String HIERARCHY_TAB = "hierarchy.tab";
|
||||
private final static String BACK_HIERARCHY_TAB = "back.hierarchy.tab";
|
||||
private final static String CLASS_DEF_TAB = "class.def.tab";
|
||||
private final static String BACK_CLASS_DEF_TAB = "back.class.def.tab";
|
||||
public static final String VERSION_FILE = ".version";
|
||||
|
||||
private final IntObjectPersistentMultiMaplet<LightRef> myReferenceMap;
|
||||
private final ObjectObjectPersistentMultiMaplet<LightDefinition, LightRef> myHierarchyMap;
|
||||
|
||||
private final ObjectObjectPersistentMultiMaplet<LightRef, Integer> myBackwardReferenceMap;
|
||||
private final ObjectObjectPersistentMultiMaplet<LightRef, LightDefinition> myBackwardHierarchyMap;
|
||||
|
||||
private final ObjectObjectPersistentMultiMaplet<LightRef, Integer> myBackwardClassDefinitionMap;
|
||||
private final IntObjectPersistentMultiMaplet<LightRef> myClassDefinitionMap;
|
||||
private final static String NAME_ENUM_TAB = "name.tab";
|
||||
|
||||
private static final String VERSION_FILE = ".version";
|
||||
private final Map<ID<?, ?>, InvertedIndex<?, ?, CompiledFileData>> myIndices;
|
||||
private final ByteArrayEnumerator myNameEnumerator;
|
||||
private final PersistentStringEnumerator myFilePathEnumerator;
|
||||
|
||||
private final File myIndicesDir;
|
||||
|
||||
private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (myNameEnumerator) {
|
||||
if (!myNameEnumerator.isClosed()) {
|
||||
myNameEnumerator.force();
|
||||
}
|
||||
}
|
||||
synchronized (myFilePathEnumerator) {
|
||||
if (!myFilePathEnumerator.isClosed()) {
|
||||
myFilePathEnumerator.force();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
private volatile boolean myRebuildRequired;
|
||||
|
||||
public CompilerBackwardReferenceIndex(File buildDir) {
|
||||
myIndicesDir = getIndexDir(buildDir);
|
||||
@@ -67,7 +70,7 @@ public class CompilerBackwardReferenceIndex {
|
||||
}
|
||||
try {
|
||||
if (versionDiffers(buildDir)) {
|
||||
FileUtil.writeToFile(new File(myIndicesDir, VERSION_FILE), String.valueOf(VERSION));
|
||||
FileUtil.writeToFile(new File(myIndicesDir, VERSION_FILE), String.valueOf(CompilerIndices.VERSION));
|
||||
}
|
||||
myFilePathEnumerator = new PersistentStringEnumerator(new File(myIndicesDir, FILE_ENUM_TAB)) {
|
||||
@Override
|
||||
@@ -76,68 +79,13 @@ public class CompilerBackwardReferenceIndex {
|
||||
}
|
||||
};
|
||||
|
||||
final KeyDescriptor<LightRef> lightUsageDescriptor = new LightRefDescriptor();
|
||||
final KeyDescriptor<LightDefinition> defDescriptor = LightDefinition.createDescriptor(lightUsageDescriptor);
|
||||
myIndices = new HashMap<ID<?, ?>, InvertedIndex<?, ?, CompiledFileData>>();
|
||||
for (IndexExtension<LightRef, ?, CompiledFileData> indexExtension : CompilerIndices.getIndices()) {
|
||||
//noinspection unchecked
|
||||
myIndices.put(indexExtension.getName(), new CompilerMapReduceIndex(indexExtension, myIndicesDir));
|
||||
}
|
||||
|
||||
myBackwardReferenceMap = new ObjectObjectPersistentMultiMaplet<LightRef, Integer>(new File(myIndicesDir, BACK_USAGES_TAB),
|
||||
lightUsageDescriptor,
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
new CollectionFactory<Integer>() {
|
||||
@Override
|
||||
public Collection<Integer> create() {
|
||||
return new THashSet<Integer>();
|
||||
}
|
||||
});
|
||||
myBackwardHierarchyMap = new ObjectObjectPersistentMultiMaplet<LightRef, LightDefinition>(new File(myIndicesDir, BACK_HIERARCHY_TAB),
|
||||
lightUsageDescriptor,
|
||||
defDescriptor,
|
||||
new CollectionFactory<LightDefinition>() {
|
||||
@Override
|
||||
public Collection<LightDefinition> create() {
|
||||
return new THashSet<LightDefinition>();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
myReferenceMap = new IntObjectPersistentMultiMaplet<LightRef>(new File(myIndicesDir, USAGES_TAB),
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
lightUsageDescriptor, new CollectionFactory<LightRef>() {
|
||||
@Override
|
||||
public Collection<LightRef> create() {
|
||||
return new THashSet<LightRef>();
|
||||
}
|
||||
});
|
||||
myHierarchyMap = new ObjectObjectPersistentMultiMaplet<LightDefinition, LightRef>(new File(myIndicesDir, HIERARCHY_TAB),
|
||||
defDescriptor,
|
||||
lightUsageDescriptor,
|
||||
new CollectionFactory<LightRef>() {
|
||||
@Override
|
||||
public Collection<LightRef> create() {
|
||||
return new THashSet<LightRef>();
|
||||
}
|
||||
});
|
||||
|
||||
myClassDefinitionMap = new IntObjectPersistentMultiMaplet<LightRef>(new File(myIndicesDir, CLASS_DEF_TAB),
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
lightUsageDescriptor,
|
||||
new CollectionFactory<LightRef>() {
|
||||
@Override
|
||||
public Collection<LightRef> create() {
|
||||
return new THashSet<LightRef>();
|
||||
}
|
||||
});
|
||||
|
||||
myBackwardClassDefinitionMap = new ObjectObjectPersistentMultiMaplet<LightRef, Integer>(new File(myIndicesDir, BACK_CLASS_DEF_TAB),
|
||||
lightUsageDescriptor,
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
new CollectionFactory<Integer>() {
|
||||
@Override
|
||||
public Collection<Integer> create() {
|
||||
return new THashSet<Integer>();
|
||||
}
|
||||
});
|
||||
|
||||
myNameEnumerator = new ByteArrayEnumerator(new File(myIndicesDir, INCOMPLETE_FILES_TAB));
|
||||
myNameEnumerator = new ByteArrayEnumerator(new File(myIndicesDir, NAME_ENUM_TAB));
|
||||
}
|
||||
catch (IOException e) {
|
||||
removeIndexFiles(myIndicesDir);
|
||||
@@ -145,34 +93,13 @@ public class CompilerBackwardReferenceIndex {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObjectObjectPersistentMultiMaplet<LightRef, Integer> getBackwardReferenceMap() {
|
||||
return myBackwardReferenceMap;
|
||||
Collection<InvertedIndex<?, ?, CompiledFileData>> getIndices() {
|
||||
return myIndices.values();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObjectObjectPersistentMultiMaplet<LightRef, LightDefinition> getBackwardHierarchyMap() {
|
||||
return myBackwardHierarchyMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IntObjectPersistentMultiMaplet<LightRef> getReferenceMap() {
|
||||
return myReferenceMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObjectObjectPersistentMultiMaplet<LightDefinition, LightRef> getHierarchyMap() {
|
||||
return myHierarchyMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObjectObjectPersistentMultiMaplet<LightRef, Integer> getBackwardClassDefinitionMap() {
|
||||
return myBackwardClassDefinitionMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IntObjectPersistentMultiMaplet<LightRef> getClassDefinitionMap() {
|
||||
return myClassDefinitionMap;
|
||||
public <K, V> InvertedIndex<K, V, CompiledFileData> get(ID<K, V> key) {
|
||||
//noinspection unchecked
|
||||
return (InvertedIndex<K, V, CompiledFileData>)myIndices.get(key);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -186,32 +113,22 @@ public class CompilerBackwardReferenceIndex {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
myLowMemoryWatcher.stop();
|
||||
final CommonProcessors.FindFirstProcessor<BuildDataCorruptedException> exceptionProc =
|
||||
new CommonProcessors.FindFirstProcessor<BuildDataCorruptedException>();
|
||||
close(myFilePathEnumerator, exceptionProc);
|
||||
close(myBackwardHierarchyMap, exceptionProc);
|
||||
close(myBackwardReferenceMap, exceptionProc);
|
||||
close(myBackwardClassDefinitionMap, exceptionProc);
|
||||
close(myHierarchyMap, exceptionProc);
|
||||
close(myReferenceMap, exceptionProc);
|
||||
close(myClassDefinitionMap, exceptionProc);
|
||||
close(myNameEnumerator, exceptionProc);
|
||||
for (InvertedIndex<?, ?, CompiledFileData> index : myIndices.values()) {
|
||||
close(index, exceptionProc);
|
||||
}
|
||||
final BuildDataCorruptedException exception = exceptionProc.getFoundValue();
|
||||
if (exception != null) {
|
||||
removeIndexFiles(myIndicesDir);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
void flush() {
|
||||
myBackwardHierarchyMap.flush(false);
|
||||
myBackwardReferenceMap.flush(false);
|
||||
myBackwardClassDefinitionMap.flush(false);
|
||||
myHierarchyMap.flush(false);
|
||||
myReferenceMap.flush(false);
|
||||
myClassDefinitionMap.flush(false);
|
||||
myNameEnumerator.force();
|
||||
myFilePathEnumerator.force();
|
||||
if (myRebuildRequired) {
|
||||
removeIndexFiles(myIndicesDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeIndexFiles(File buildDir) {
|
||||
@@ -232,89 +149,78 @@ public class CompilerBackwardReferenceIndex {
|
||||
public static boolean versionDiffers(@NotNull File buildDir) {
|
||||
File versionFile = new File(getIndexDir(buildDir), VERSION_FILE);
|
||||
try {
|
||||
return Integer.parseInt(FileUtil.loadFile(versionFile)) != VERSION;
|
||||
return Integer.parseInt(FileUtil.loadFile(versionFile)) != CompilerIndices.VERSION;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void close(Closeable closeable, Processor<BuildDataCorruptedException> exceptionProcessor) {
|
||||
private static void close(InvertedIndex<?, ?, CompiledFileData> index, CommonProcessors.FindFirstProcessor<BuildDataCorruptedException> exceptionProcessor) {
|
||||
try {
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
exceptionProcessor.process(new BuildDataCorruptedException(e));
|
||||
}
|
||||
}
|
||||
|
||||
private static void close(CloseableMaplet closeable, Processor<BuildDataCorruptedException> exceptionProcessor) {
|
||||
try {
|
||||
closeable.close();
|
||||
index.dispose();
|
||||
}
|
||||
catch (BuildDataCorruptedException e) {
|
||||
exceptionProcessor.process(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LightDefinition {
|
||||
private final LightRef myUsage;
|
||||
private final int myFileId;
|
||||
|
||||
LightDefinition(LightRef usage, int id) {
|
||||
myUsage = usage;
|
||||
myFileId = id;
|
||||
}
|
||||
|
||||
public LightRef getRef() {
|
||||
return myUsage;
|
||||
}
|
||||
|
||||
public int getFileId() {
|
||||
return myFileId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
LightDefinition that = (LightDefinition)o;
|
||||
|
||||
if (!myUsage.equals(that.myUsage)) return false;
|
||||
if (myFileId != that.myFileId) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myUsage.hashCode();
|
||||
}
|
||||
|
||||
private static KeyDescriptor<LightDefinition> createDescriptor(final DataExternalizer<LightRef> usageDataExternalizer) {
|
||||
return new KeyDescriptor<LightDefinition>() {
|
||||
@Override
|
||||
public int getHashCode(LightDefinition value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(LightDefinition val1, LightDefinition val2) {
|
||||
return val1.equals(val2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, LightDefinition value) throws IOException {
|
||||
usageDataExternalizer.save(out, value.getRef());
|
||||
EnumeratorIntegerDescriptor.INSTANCE.save(out, value.getFileId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LightDefinition read(@NotNull DataInput in) throws IOException {
|
||||
return new LightDefinition(usageDataExternalizer.read(in), EnumeratorIntegerDescriptor.INSTANCE.read(in));
|
||||
}
|
||||
};
|
||||
private static void close(Closeable closeable, Processor<BuildDataCorruptedException> exceptionProcessor) {
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
exceptionProcessor.process(new BuildDataCorruptedException(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CompilerMapReduceIndex<Key, Value> extends MapReduceIndex<Key, Value, CompiledFileData> {
|
||||
public CompilerMapReduceIndex(@NotNull final IndexExtension<Key, Value, CompiledFileData> extension,
|
||||
@NotNull final File indexDir)
|
||||
throws IOException {
|
||||
super(extension,
|
||||
createIndexStorage(extension.getKeyDescriptor(), extension.getValueExternalizer(), extension.getName(), indexDir),
|
||||
new MapBasedForwardIndex<Key, Value>(extension) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PersistentHashMap<Integer, Collection<Key>> createMap() throws IOException {
|
||||
ID<Key, Value> id = extension.getName();
|
||||
return new PersistentHashMap<Integer, Collection<Key>>(new File(indexDir, id + ".inputs"),
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
new InputIndexDataExternalizer<Key>(extension.getKeyDescriptor(),
|
||||
id));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanceled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void requestRebuild(Exception e) {
|
||||
myRebuildRequired = true;
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static <Key, Value> IndexStorage<Key, Value> createIndexStorage(@NotNull KeyDescriptor<Key> keyDescriptor,
|
||||
@NotNull DataExternalizer<Value> valueExternalizer,
|
||||
@NotNull ID<Key, Value> indexId,
|
||||
@NotNull File indexDir) throws IOException {
|
||||
return new MapIndexStorage<Key, Value>(new File(indexDir, indexId.toString()),
|
||||
keyDescriptor,
|
||||
valueExternalizer,
|
||||
16 * 1024,
|
||||
false) {
|
||||
@Override
|
||||
public void checkCanceled() {
|
||||
//TODO
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ import java.io.IOException;
|
||||
|
||||
import static org.jetbrains.jps.backwardRefs.LightRef.*;
|
||||
|
||||
final class LightRefDescriptor implements KeyDescriptor<LightRef>, DifferentSerializableBytesImplyNonEqualityPolicy {
|
||||
public final class LightRefDescriptor implements KeyDescriptor<LightRef>, DifferentSerializableBytesImplyNonEqualityPolicy {
|
||||
public static final LightRefDescriptor INSTANCE = new LightRefDescriptor();
|
||||
|
||||
@Override
|
||||
public int getHashCode(LightRef value) {
|
||||
return value.hashCode();
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.jetbrains.jps.backwardRefs.index;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class CompiledFileData {
|
||||
private final Map<LightRef, Collection<LightRef>> myBackwardHierarchyMap;
|
||||
private final Map<LightRef, Void> myReferences;
|
||||
private final Map<LightRef, Void> myDefinitions;
|
||||
|
||||
public CompiledFileData(@NotNull Map<LightRef, Collection<LightRef>> backwardHierarchyMap,
|
||||
@NotNull Map<LightRef, Void> references,
|
||||
@NotNull Map<LightRef, Void> definitions) {
|
||||
myBackwardHierarchyMap = backwardHierarchyMap;
|
||||
myReferences = references;
|
||||
myDefinitions = definitions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<LightRef, Collection<LightRef>> getBackwardHierarchy() {
|
||||
return myBackwardHierarchyMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<LightRef, Void> getReferences() {
|
||||
return myReferences;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<LightRef, Void> getDefinitions() {
|
||||
return myDefinitions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.jetbrains.jps.backwardRefs.index;
|
||||
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.DataIndexer;
|
||||
import com.intellij.util.indexing.ID;
|
||||
import com.intellij.util.indexing.IndexExtension;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.io.VoidDataExternalizer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.backwardRefs.LightRef;
|
||||
import org.jetbrains.jps.backwardRefs.LightRefDescriptor;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CompilerIndices {
|
||||
//TODO manage version separately
|
||||
public final static int VERSION = 0;
|
||||
|
||||
public final static ID<LightRef, Void> BACK_USAGES = ID.create("back.refs");
|
||||
public final static ID<LightRef, Collection<LightRef>> BACK_HIERARCHY = ID.create("back.hierarchy");
|
||||
public final static ID<LightRef, Void> BACK_CLASS_DEF = ID.create("back.class.def");
|
||||
|
||||
public static List<IndexExtension<LightRef, ?, CompiledFileData>> getIndices() {
|
||||
return ContainerUtil.list(createBackwardClassDefinitionExtension(), createBackwardUsagesExtension(), createBackwardHierarchyExtension());
|
||||
}
|
||||
|
||||
private static IndexExtension<LightRef, Void, CompiledFileData> createBackwardUsagesExtension() {
|
||||
return new IndexExtension<LightRef, Void, CompiledFileData>() {
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ID<LightRef, Void> getName() {
|
||||
return BACK_USAGES;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataIndexer<LightRef, Void, CompiledFileData> getIndexer() {
|
||||
return new DataIndexer<LightRef, Void, CompiledFileData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<LightRef, Void> map(@NotNull CompiledFileData inputData) {
|
||||
return inputData.getReferences();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KeyDescriptor<LightRef> getKeyDescriptor() {
|
||||
return LightRefDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataExternalizer<Void> getValueExternalizer() {
|
||||
return VoidDataExternalizer.INSTANCE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static IndexExtension<LightRef, Collection<LightRef>, CompiledFileData> createBackwardHierarchyExtension() {
|
||||
return new IndexExtension<LightRef, Collection<LightRef>, CompiledFileData>() {
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ID<LightRef, Collection<LightRef>> getName() {
|
||||
return BACK_HIERARCHY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataIndexer<LightRef, Collection<LightRef>, CompiledFileData> getIndexer() {
|
||||
return new DataIndexer<LightRef, Collection<LightRef>, CompiledFileData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<LightRef, Collection<LightRef>> map(@NotNull CompiledFileData inputData) {
|
||||
return inputData.getBackwardHierarchy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KeyDescriptor<LightRef> getKeyDescriptor() {
|
||||
return LightRefDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataExternalizer<Collection<LightRef>> getValueExternalizer() {
|
||||
return new DataExternalizer<Collection<LightRef>>() {
|
||||
@Override
|
||||
public void save(@NotNull final DataOutput out, Collection<LightRef> value) throws IOException {
|
||||
DataInputOutputUtil.writeSeq(out, value, new ThrowableConsumer<LightRef, IOException>() {
|
||||
@Override
|
||||
public void consume(LightRef lightRef) throws IOException {
|
||||
LightRefDescriptor.INSTANCE.save(out, lightRef);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LightRef> read(@NotNull final DataInput in) throws IOException {
|
||||
return DataInputOutputUtil.readSeq(in, new ThrowableComputable<LightRef, IOException>() {
|
||||
@Override
|
||||
public LightRef compute() throws IOException {
|
||||
return LightRefDescriptor.INSTANCE.read(in);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static IndexExtension<LightRef, Void, CompiledFileData> createBackwardClassDefinitionExtension() {
|
||||
return new IndexExtension<LightRef, Void, CompiledFileData>() {
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ID<LightRef, Void> getName() {
|
||||
return BACK_CLASS_DEF;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataIndexer<LightRef, Void, CompiledFileData> getIndexer() {
|
||||
return new DataIndexer<LightRef, Void, CompiledFileData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<LightRef, Void> map(@NotNull CompiledFileData inputData) {
|
||||
return inputData.getDefinitions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KeyDescriptor<LightRef> getKeyDescriptor() {
|
||||
return LightRefDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataExternalizer<Void> getValueExternalizer() {
|
||||
return VoidDataExternalizer.INSTANCE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import java.io.IOException;
|
||||
* @author nik
|
||||
*/
|
||||
public class BuildDataCorruptedException extends RuntimeException {
|
||||
public BuildDataCorruptedException(IOException cause) {
|
||||
public BuildDataCorruptedException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,17 @@ package org.jetbrains.references
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.indexing.ID
|
||||
import com.intellij.util.indexing.impl.MapIndexStorage
|
||||
import com.intellij.util.indexing.impl.MapReduceIndex
|
||||
import com.intellij.util.io.PersistentStringEnumerator
|
||||
import com.sun.tools.javac.util.Convert
|
||||
import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex
|
||||
import org.jetbrains.jps.backwardRefs.LightRef
|
||||
import org.jetbrains.jps.backwardRefs.index.CompiledFileData
|
||||
import org.jetbrains.jps.backwardRefs.index.CompilerIndices
|
||||
import org.jetbrains.jps.builders.JpsBuildTestCase
|
||||
import org.jetbrains.jps.builders.TestProjectBuilderLogger
|
||||
import org.jetbrains.jps.builders.logging.BuildLoggingManager
|
||||
@@ -83,14 +88,17 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
val result = StringBuilder()
|
||||
result.append("Backward Hierarchy:\n")
|
||||
val hierarchyText = mutableListOf<String>()
|
||||
index.backwardHierarchyMap.forEachEntry { superClass, inheritors ->
|
||||
storage(index, CompilerIndices.BACK_HIERARCHY).processKeys { superClass ->
|
||||
val superClassName = superClass.asText(nameEnumerator)
|
||||
val inheritorsText = mutableListOf<String>()
|
||||
inheritors.forEach { id ->
|
||||
inheritorsText.add(id.asText(nameEnumerator))
|
||||
index[CompilerIndices.BACK_HIERARCHY].getData(superClass).forEach { i, children ->
|
||||
children.mapTo(inheritorsText) { it.asText(nameEnumerator) }
|
||||
true
|
||||
}
|
||||
if (!inheritorsText.isEmpty()) {
|
||||
inheritorsText.sort()
|
||||
hierarchyText.add(superClassName + " -> " + inheritorsText.joinToString(separator = " "))
|
||||
}
|
||||
inheritorsText.sort()
|
||||
hierarchyText.add(superClassName + " -> " + inheritorsText.joinToString(separator = " "))
|
||||
true
|
||||
}
|
||||
hierarchyText.sort()
|
||||
@@ -98,13 +106,20 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
|
||||
result.append("\n\nBackward References:\n")
|
||||
val referencesText = mutableListOf<String>()
|
||||
index.backwardReferenceMap.forEachEntry { usage, files ->
|
||||
storage(index, CompilerIndices.BACK_USAGES).processKeys { usage ->
|
||||
val referents = mutableListOf<String>()
|
||||
files.forEach { id ->
|
||||
referents.add(id.asFileName(fileEnumerator))
|
||||
val valueIt = index[CompilerIndices.BACK_USAGES].getData(usage).valueIterator
|
||||
while (valueIt.hasNext()) {
|
||||
valueIt.next()
|
||||
val files = valueIt.inputIdsIterator
|
||||
while (files.hasNext()) {
|
||||
referents.add(files.next().asFileName(fileEnumerator))
|
||||
}
|
||||
}
|
||||
if (!referents.isEmpty()) {
|
||||
referents.sort()
|
||||
referencesText.add(usage.asText(nameEnumerator) + " in " + referents.joinToString(separator = " "))
|
||||
}
|
||||
referents.sort()
|
||||
referencesText.add(usage.asText(nameEnumerator) + " in " + referents.joinToString(separator = " "))
|
||||
true
|
||||
}
|
||||
referencesText.sort()
|
||||
@@ -112,13 +127,20 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
|
||||
result.append("\n\nClass Definitions:\n")
|
||||
val classDefs = mutableListOf<String>()
|
||||
index.backwardClassDefinitionMap.forEachEntry { usage, files ->
|
||||
storage(index, CompilerIndices.BACK_CLASS_DEF).processKeys { usage ->
|
||||
val definitionFiles = mutableListOf<String>()
|
||||
files.forEach { id ->
|
||||
definitionFiles.add(id.asFileName(fileEnumerator))
|
||||
val valueIt = index[CompilerIndices.BACK_CLASS_DEF].getData(usage).valueIterator
|
||||
while (valueIt.hasNext()) {
|
||||
valueIt.next()
|
||||
val files = valueIt.inputIdsIterator
|
||||
while (files.hasNext()) {
|
||||
definitionFiles.add(files.next().asFileName(fileEnumerator))
|
||||
}
|
||||
}
|
||||
if (!definitionFiles.isEmpty()) {
|
||||
definitionFiles.sort()
|
||||
classDefs.add(usage.asText(nameEnumerator) + " in " + definitionFiles.joinToString(separator = " "))
|
||||
}
|
||||
definitionFiles.sort()
|
||||
classDefs.add(usage.asText(nameEnumerator) + " in " + definitionFiles.joinToString(separator = " "))
|
||||
true
|
||||
}
|
||||
classDefs.sort()
|
||||
@@ -130,12 +152,12 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> storage(index: CompilerBackwardReferenceIndex, id: ID<K, V>) = (index[id] as MapReduceIndex<K, V, CompiledFileData>).storage as MapIndexStorage<K, V>
|
||||
|
||||
private fun getTestDataPath() = testDataRootPath + "/" + getTestName(true) + "/"
|
||||
|
||||
private fun Int.asName(byteArrayEnumerator: ByteArrayEnumerator): String = Convert.utf2string(byteArrayEnumerator.valueOf(this))
|
||||
|
||||
private fun CompilerBackwardReferenceIndex.LightDefinition.asText(byteArrayEnumerator: ByteArrayEnumerator) = this.ref.asText(byteArrayEnumerator)
|
||||
|
||||
private fun LightRef.asText(byteArrayEnumerator: ByteArrayEnumerator): String =
|
||||
when (this) {
|
||||
is LightRef.JavaLightMethodRef -> "${this.owner.name.asName(byteArrayEnumerator)}.${this.name.asName(byteArrayEnumerator)}(${this.parameterCount})"
|
||||
|
||||
Reference in New Issue
Block a user