stub hierarchy: serialize hashes instead of names for faster reading, smaller index data and a very unlikely collision probability

This commit is contained in:
peter
2016-06-24 17:02:24 +02:00
parent 7f70956afe
commit b4a2271239
7 changed files with 149 additions and 149 deletions
@@ -20,7 +20,6 @@ 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.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
@@ -89,7 +88,7 @@ public class HierarchyServiceImpl extends HierarchyService {
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);
QualifiedName pkg = unit.myPackageName.length == 0 ? null : names.myNamesEnumerator.getFullName(unit.myPackageName, true);
stubEnter.unitEnter(Translator.internNames(names, unit, fileId, pkg));
}
return true;
@@ -16,14 +16,12 @@
package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public class NameEnvironment extends UserDataHolderBase {
public final QualifiedName empty;
public final QualifiedName java_lang_Object;
public final QualifiedName java_lang_Enum;
@@ -40,22 +38,7 @@ public class NameEnvironment extends UserDataHolderBase {
@Nullable
public QualifiedName fromString(String s, boolean create) {
List<String> comps = StringUtil.split(s, ".");
int[] ids = new int[comps.size()];
for (int i = 0; i < comps.size(); i++) {
int name = simpleName(comps.get(i), create);
if (name == NamesEnumerator.NO_NAME) {
return null;
}
ids[i] = name;
}
return myNamesEnumerator.getFullName(ids, create);
}
public int simpleName(String s, boolean create) {
if (s == null)
return NamesEnumerator.NO_NAME;
return myNamesEnumerator.getSimpleName(s, create);
return myNamesEnumerator.getFullName(IndexTree.hashQualifiedName(s), create);
}
public QualifiedName prefix(QualifiedName name) {
@@ -15,31 +15,15 @@
*/
package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.util.ArrayUtil;
import gnu.trove.TObjectHashingStrategy;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
public class NamesEnumerator {
final static int NO_NAME = 0;
private TObjectIntHashMap<byte[]> myAsciiMap = new TObjectIntHashMap<byte[]>(new TObjectHashingStrategy<byte[]>() {
@Override
public int computeHashCode(byte[] object) {
return Arrays.hashCode(object);
}
@Override
public boolean equals(byte[] o1, byte[] o2) {
return Arrays.equals(o1, o2);
}
});
private TObjectIntHashMap<String> myNonAsciiMap = new TObjectIntHashMap<String>();
TObjectIntHashMap<int[]> fullNameMap = new TObjectIntHashMap<int[]>(new TObjectHashingStrategy<int[]>() {
private final TObjectIntHashMap<int[]> myFullNameMap = new TObjectIntHashMap<int[]>(new TObjectHashingStrategy<int[]>() {
@Override
public int computeHashCode(int[] object) {
return Arrays.hashCode(object);
@@ -50,38 +34,17 @@ public class NamesEnumerator {
return Arrays.equals(o1, o2);
}
});
private QualifiedName[] myQualifiedNames = new QualifiedName[0x8000];
QualifiedName qualifiedName(int id) {
return myQualifiedNames[id];
}
public int getSimpleName(String s, boolean create) {
byte[] bytes = convertToBytesIfAsciiString(s);
if (bytes != null) {
int id = myAsciiMap.get(bytes);
if (id == 0 && create) {
id = myAsciiMap.size() + myNonAsciiMap.size() + 1;
myAsciiMap.put(bytes, id);
}
return id;
}
else {
int id = myNonAsciiMap.get(s);
if (id == 0 && create) {
id = myAsciiMap.size() + myNonAsciiMap.size() + 1;
myNonAsciiMap.put(s, id);
}
return id;
}
}
public QualifiedName getFullName(int[] ids, boolean create) {
int id = fullNameMap.get(ids);
int id = myFullNameMap.get(ids);
if (id == 0 && create) {
id = fullNameMap.size() + 1;
fullNameMap.put(ids, id);
id = myFullNameMap.size() + 1;
myFullNameMap.put(ids, id);
ensureFullCapacity(id);
myQualifiedNames[id] = new QualifiedName(id, ids);
}
@@ -104,20 +67,4 @@ public class NamesEnumerator {
return currentLength;
}
@Nullable
public static byte[] convertToBytesIfAsciiString(CharSequence name) {
int length = name.length();
if (length == 0) return ArrayUtil.EMPTY_BYTE_ARRAY;
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
char c = name.charAt(i);
if (c >= 128) {
return null;
}
bytes[i] = (byte)c;
}
return bytes;
}
}
@@ -74,7 +74,7 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<Integer, IndexTr
@Override
public int getVersion() {
return IndexTree.STUB_HIERARCHY_ENABLED ? 3 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
return IndexTree.STUB_HIERARCHY_ENABLED ? 4 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
}
@NotNull
@@ -16,15 +16,12 @@
package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.psi.stubsHierarchy.stubs.*;
import com.intellij.util.BitUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class Translator {
private static final Key<long[]> DEFAULT_JAVA_IMPORTS_KEY = Key.create("java_imports");
@@ -91,11 +88,10 @@ public class Translator {
}
private static ClassDeclaration processClassDecl(NameEnvironment nameEnvironment, int fileId, IndexTree.ClassDecl def) {
String stubName = def.myName;
int name = stubName == null ? 0 : nameEnvironment.simpleName(stubName, true);
int name = def.myName;
ArrayList<QualifiedName> superList = new ArrayList<QualifiedName>();
for (String aSuper : def.mySupers) {
superList.add(id(nameEnvironment, aSuper));
for (int[] aSuper : def.mySupers) {
superList.add(nameEnvironment.concat(aSuper, true));
}
if (BitUtil.isSet(def.myMods, IndexTree.ENUM)) {
superList.add(nameEnvironment.java_lang_Enum);
@@ -130,21 +126,8 @@ public class Translator {
}
private static long processImport(NameEnvironment nameEnvironment, IndexTree.Import anImport) {
QualifiedName fullname = nameEnvironment.fromString(anImport.myFullname, true);
int aliasName = anImport.myAlias == null ? 0 : nameEnvironment.simpleName(anImport.myAlias, true);
return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, aliasName);
QualifiedName fullname = nameEnvironment.myNamesEnumerator.getFullName(anImport.myFullname, true);
return Import.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, anImport.myAlias);
}
private static QualifiedName id(NameEnvironment nameEnvironment, String s) {
s = PsiNameHelper.getQualifiedClassName(s, true);
List<String> ids = StringUtil.split(s, ".");
int[] comps = new int[ids.size()];
int i = 0;
for (String id : ids) {
int name = nameEnvironment.simpleName(id, true);
comps[i] = name;
i++;
}
return nameEnvironment.concat(comps, true);
}
}