Shared indices: add "dumpIndex" command used to generate indices for JDKs.

GitOrigin-RevId: 4049b6c92024d8cec2390ce6fe4b5f493a80d388
This commit is contained in:
Sergey Patrikeev
2019-12-27 14:07:55 +00:00
committed by intellij-monorepo-bot
parent 76bacd6626
commit 403bc56a58
5 changed files with 414 additions and 163 deletions
@@ -0,0 +1,119 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.internal
import com.intellij.jdkDownloader.JdkInstallRequest
import com.intellij.jdkDownloader.JdkInstaller
import com.intellij.jdkDownloader.JdkListDownloader
import com.intellij.openapi.application.ApplicationStarter
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
import com.intellij.openapi.roots.OrderRootType
import com.intellij.util.io.createDirectories
import com.intellij.util.io.delete
import com.intellij.util.io.exists
import com.intellij.util.io.isDirectory
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.system.exitProcess
class DumpIndexStarter : ApplicationStarter {
override fun getCommandName() = "dumpIndex"
private companion object {
private val LOG = Logger.getInstance("dumpIndex")
fun getRequiredProperty(name: String): String =
System.getProperty(name) ?: throw IllegalArgumentException("'$name' is not specified")
val outputPath: Path by lazy {
val path = Paths.get(getRequiredProperty("dump.index.output.path"))
path.createDirectories()
}
val removeDownloadedJdks: Boolean by lazy {
System.getProperty("dump.index.remove.downloaded.jdks", "false")!!.toBoolean()
}
fun info(message: String) {
println(message)
}
}
private fun dumpOptions() {
info("DumpIndex options")
info("Output path: $outputPath")
}
override fun main(args: Array<out String>) {
dumpOptions()
try {
start()
info("DumpIndex finished")
exitProcess(0)
}
catch (e: Throwable) {
info("DumpIndex failed")
e.printStackTrace()
exitProcess(-1)
}
}
private fun start() {
val tempPath = outputPath.resolve("temp")
val projectPath = tempPath.resolve("project").createDirectories()
val jdksPath = tempPath.resolve("jdks").createDirectories()
info("Downloading list of available JDKs")
val jdkItems = JdkListDownloader.downloadModelForJdkInstaller(EmptyProgressIndicator())
info("Available JDKs: " + jdkItems.joinToString { it.fullPresentationText })
val project = ProjectManager.getInstance().createProject("tempProject", projectPath.toAbsolutePath().toString())
if (project == null) {
LOG.error("Failed to create temp project")
return
}
val jdkType = JavaSdk.getInstance()
for (jdkItem in jdkItems) {
val jdkPath = jdksPath.resolve(jdkItem.installFolderName)
if (jdkPath.isDirectory()) {
info("JDK ${jdkItem.fullPresentationText} is already downloaded")
}
else {
info("Downloading ${jdkItem.fullPresentationText} to $jdkPath")
val jdkInstallRequest = JdkInstallRequest(jdkItem, jdkPath.toFile())
JdkInstaller.installJdk(jdkInstallRequest, EmptyProgressIndicator())
}
info("Creating SDK from ${jdkItem.fullPresentationText}")
val sdk = SdkConfigurationUtil.createAndAddSDK(jdkPath.toAbsolutePath().toString(), jdkType)
if (sdk == null) {
LOG.warn("Failed to create JDK for ${jdkItem.fullPresentationText}")
continue
}
val jdkIndicesPath = outputPath.resolve(jdkItem.installFolderName)
if (jdkIndicesPath.exists()) {
info("Delete previous indices in $jdkIndicesPath")
}
info("Building indices for ${jdkItem.fullPresentationText} to $jdkIndicesPath")
try {
val roots = (sdk.rootProvider.getFiles(OrderRootType.CLASSES) + sdk.rootProvider.getFiles(OrderRootType.SOURCES)).toSet()
val indexChunk = DumpIndexAction.IndexChunk(roots, jdkItem.installFolderName)
DumpIndexAction.exportSingleIndexChunk(project, indexChunk, jdkIndicesPath, EmptyProgressIndicator())
}
finally {
SdkConfigurationUtil.removeSdk(sdk)
if (removeDownloadedJdks) {
jdkPath.delete()
}
}
}
}
}
@@ -1972,6 +1972,8 @@
<commandLineInspectionProjectConfigurator implementation="com.intellij.codeInspection.JavaCommandLineInspectionProjectConfigurator"/>
<compiler.task implementation="com.intellij.execution.scratch.JavaScratchCompilationSupport"/>
<appStarter implementation="com.intellij.internal.DumpIndexStarter"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains">
@@ -22,6 +22,9 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.newvfs.persistent.ContentHashesUtil;
import com.intellij.psi.SingleRootFileViewProvider;
import com.intellij.psi.impl.JavaSimplePropertyIndex;
import com.intellij.psi.impl.cache.impl.id.IdIndex;
import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
@@ -35,6 +38,7 @@ import com.intellij.util.indexing.FileBasedIndexExtension;
import com.intellij.util.indexing.ID;
import com.intellij.util.indexing.IndexableSetContributor;
import com.intellij.util.indexing.hash.HashBasedIndexGenerator;
import com.intellij.util.io.PathKt;
import com.intellij.util.io.zip.JBZipEntry;
import com.intellij.util.io.zip.JBZipFile;
import gnu.trove.THashSet;
@@ -58,6 +62,36 @@ public class DumpIndexAction extends AnAction {
public void actionPerformed(@NotNull AnActionEvent event) {
Project project = event.getProject();
if (project == null) return;
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
descriptor.withTitle("Select Index Dump Directory");
VirtualFile file = FileChooser.chooseFile(descriptor, project, null);
if (file != null) {
ProgressManager.getInstance().run(new Task.Modal(project, "Exporting Indexes..." , true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
File out = VfsUtilCore.virtualToIoFile(file);
FileUtil.delete(out);
exportIndices(project, out.toPath(), indicator);
}
});
}
}
public static void exportIndices(@NotNull Project project, @NotNull Path out, @NotNull ProgressIndicator indicator) {
List<IndexChunk> chunks = ReadAction.compute(() -> buildChunks(project));
exportIndices(project, chunks, out, indicator);
}
public static void exportSingleIndexChunk(@NotNull Project project,
@NotNull IndexChunk chunk,
@NotNull Path out,
@NotNull ProgressIndicator indicator) {
exportIndices(project, Collections.singletonList(chunk), out, indicator);
}
@NotNull
private static List<IndexChunk> buildChunks(Project project) {
Collection<IndexChunk> projectChunks = Arrays
.stream(ModuleManager.getInstance(project).getModules())
.flatMap(m -> IndexChunk.generate(m))
@@ -65,8 +99,9 @@ public class DumpIndexAction extends AnAction {
.values();
Set<VirtualFile>
additionalRoots = IndexableSetContributor.EP_NAME.extensions().flatMap(contributor -> Stream.concat(IndexableSetContributor.getRootsToIndex(contributor).stream(),
IndexableSetContributor.getProjectRootsToIndex(contributor, project).stream())).collect(
additionalRoots = IndexableSetContributor.EP_NAME.extensions().flatMap(contributor -> Stream
.concat(IndexableSetContributor.getRootsToIndex(contributor).stream(),
IndexableSetContributor.getProjectRootsToIndex(contributor, project).stream())).collect(
Collectors.toSet());
Set<VirtualFile> synthRoots = new THashSet<>();
@@ -81,41 +116,35 @@ public class DumpIndexAction extends AnAction {
}
}
List<IndexChunk> chunks = Stream.concat(projectChunks.stream(),
return Stream.concat(projectChunks.stream(),
Stream.of(new IndexChunk(additionalRoots, "ADDITIONAL"),
new IndexChunk(synthRoots, "SYNTH"))).collect(Collectors.toList());
//IndexChunk chunk = chunks.stream().reduce((c1, c2) -> IndexChunk.mergeUnsafe(c1, c2)).get();
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
descriptor.withTitle("Select Index Dump Directory");
VirtualFile file = FileChooser.chooseFile(descriptor, project, null);
if (file != null) {
ProgressManager.getInstance().run(new Task.Modal(project, "Exporting Indexes..." , true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
File out = VfsUtilCore.virtualToIoFile(file);
FileUtil.delete(out);
exportIndices(chunks, out, indicator, project);
}
});
}
}
public static void exportIndices(@NotNull List<IndexChunk> chunks,
@NotNull File out,
@NotNull ProgressIndicator indicator,
@NotNull Project project) {
private static void exportIndices(@NotNull Project project,
@NotNull List<IndexChunk> chunks,
@NotNull Path out,
@NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(false);
AtomicInteger idx = new AtomicInteger();
if (!JobLauncher.getInstance().invokeConcurrentlyUnderProgress(chunks, indicator, chunk -> {
indicator.setText("Indexing '" + chunk.getName() + "' chunk");
File chunkOut = new File(out, chunk.getName());
indicator.setText("Indexing chunk " + chunk.getName());
Path chunkRoot = out.resolve(chunk.getName());
ReadAction.run(() -> {
Stream<HashBasedIndexGenerator<?, ?>> fbIndexes = getExportableIndices(true).map(ex -> new HashBasedIndexGenerator(ex, chunkOut));
Stream<HashBasedIndexGenerator<?, ?>> stubIndex = Stream.of(new StubHashBasedIndexGenerator(chunkOut));
List<HashBasedIndexGenerator<?, ?>> indexes = Stream.concat(fbIndexes, stubIndex).collect(Collectors.toList());
HashBasedIndexGenerator.generate(chunk.getRoots(),indexes, project, chunkOut);
List<HashBasedIndexGenerator<?, ?>> fileBasedGenerators = getExportableIndices(true)
.map(extension -> getGenerator(chunkRoot, extension))
.collect(Collectors.toList());
StubHashBasedIndexGenerator stubGenerator = new StubHashBasedIndexGenerator(chunkRoot);
List<HashBasedIndexGenerator<?, ?>> allGenerators = new ArrayList<>(fileBasedGenerators);
allGenerators.add(stubGenerator);
generate(chunk, project, allGenerators, chunkRoot);
printStatistics(chunk, fileBasedGenerators, stubGenerator);
deleteEmptyIndices(fileBasedGenerators, chunkRoot.resolve("empty-indices.txt"));
deleteEmptyIndices(stubGenerator.getStubGenerators(), chunkRoot.resolve("empty-stub-indices.txt"));
});
indicator.setFraction(((double) idx.incrementAndGet()) / chunks.size());
return true;
@@ -123,16 +152,47 @@ public class DumpIndexAction extends AnAction {
throw new AssertionError();
}
zipIndexOut(out, indicator);
}
@NotNull
private static <K, V> HashBasedIndexGenerator<K, V> getGenerator(Path chunkRoot, FileBasedIndexExtension<K, V> extension) {
return new HashBasedIndexGenerator<>(extension, chunkRoot);
}
private static void deleteEmptyIndices(@NotNull List<HashBasedIndexGenerator<?, ?>> generators,
@NotNull Path dumpEmptyIndicesNamesFile) {
Set<String> emptyIndices = new HashSet<>();
for (HashBasedIndexGenerator<?, ?> generator : generators) {
if (generator.isEmpty()) {
emptyIndices.add(generator.getExtension().getName().getName());
Path indexRoot = generator.getIndexRoot();
PathKt.delete(indexRoot);
}
}
if (!emptyIndices.isEmpty()) {
String emptyIndicesText = String.join("\n", emptyIndices);
try {
PathKt.write(dumpEmptyIndicesNamesFile, emptyIndicesText);
}
catch (IOException e) {
LOG.error(e);
}
}
}
private static void zipIndexOut(@NotNull Path out, @NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(true);
indicator.setText("Zipping index pack");
File zipFile = new File(out.getAbsolutePath() + ".zip");
FileUtil.delete(zipFile);
File zipFile = new File(out.toFile().getAbsolutePath() + ".zip");
if (zipFile.exists()) {
FileUtil.delete(zipFile);
}
try (JBZipFile file = new JBZipFile(zipFile)) {
Path outPath = out.toPath();
Files.walk(outPath).forEach(p -> {
Files.walk(out).forEach(p -> {
if (Files.isDirectory(p)) return;
String relativePath = outPath.relativize(p).toString();
String relativePath = out.relativize(p).toString();
try {
JBZipEntry entry = file.getOrCreateEntry(relativePath);
entry.setMethod(ZipEntry.STORED);
@@ -148,8 +208,90 @@ public class DumpIndexAction extends AnAction {
}
}
private static void generate(@NotNull IndexChunk chunk,
@NotNull Project project,
@NotNull Collection<HashBasedIndexGenerator<?, ?>> generators,
@NotNull Path chunkOut) {
try {
ContentHashesUtil.HashEnumerator hashEnumerator = new ContentHashesUtil.HashEnumerator(chunkOut.resolve("hashes"));
try {
for (HashBasedIndexGenerator<?, ?> generator : generators) {
generator.openIndex();
}
for (VirtualFile root : chunk.getRoots()) {
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor<Boolean>() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory() && !SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
for (HashBasedIndexGenerator<?, ?> generator : generators) {
generator.indexFile(file, project, hashEnumerator);
}
}
return true;
}
});
}
}
finally {
hashEnumerator.close();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
try {
for (HashBasedIndexGenerator<?, ?> generator : generators) {
generator.closeIndex();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private static void printStatistics(@NotNull IndexChunk chunk,
@NotNull List<HashBasedIndexGenerator<?, ?>> fileBasedGenerators,
@NotNull StubHashBasedIndexGenerator stubGenerator) {
StringBuilder stats = new StringBuilder();
stats.append("Statistics for index chunk ").append(chunk.getName()).append("\n");
stats.append("File based indices (").append(fileBasedGenerators.size()).append(")");
for (HashBasedIndexGenerator<?, ?> generator : fileBasedGenerators) {
appendGeneratorStatistics(stats, generator);
}
Collection<HashBasedIndexGenerator<?, ?>> stubGenerators = stubGenerator.getStubGenerators();
stats.append("Stub indices (").append(stubGenerators.size()).append(")");
for (HashBasedIndexGenerator<?, ?> generator : stubGenerators) {
appendGeneratorStatistics(stats, generator);
}
System.out.println(stats.toString());
}
private static void appendGeneratorStatistics(@NotNull StringBuilder stringBuilder,
@NotNull HashBasedIndexGenerator<?, ?> generator) {
stringBuilder
.append(" ")
.append("Generator for ")
.append(generator.getExtension().getName().getName())
.append(" indexed ")
.append(generator.getIndexedFilesNumber())
.append(" files");
if (generator.isEmpty()) {
stringBuilder.append( "(empty result)");
}
stringBuilder.append("\n");
}
@NotNull
private static Stream<FileBasedIndexExtension> getExportableIndices(boolean all) {
private static Stream<FileBasedIndexExtension<?, ?>> getExportableIndices(boolean all) {
if (all) {
return FileBasedIndexExtension
.EXTENSION_POINT_NAME
@@ -159,7 +301,7 @@ public class DumpIndexAction extends AnAction {
}
//kt
Stream<FileBasedIndexExtension> ktIndices =
Stream<FileBasedIndexExtension<?, ?>> ktIndices =
FileBasedIndexExtension
.EXTENSION_POINT_NAME
.extensions()
@@ -171,14 +313,14 @@ public class DumpIndexAction extends AnAction {
ID.findByName("DomFileIndex"),
ID.findByName("xmlProperties"));
//xml
Stream<FileBasedIndexExtension> xmlIndices =
Stream<FileBasedIndexExtension<?, ?>> xmlIndices =
FileBasedIndexExtension
.EXTENSION_POINT_NAME
.extensions()
.filter(id -> xmlIndexIds.contains(id.getName()));
//base
Stream<FileBasedIndexExtension> coreIndices =
Stream<FileBasedIndexExtension<?, ?>> coreIndices =
FileBasedIndexExtension
.EXTENSION_POINT_NAME
.extensions()
@@ -188,7 +330,7 @@ public class DumpIndexAction extends AnAction {
ex.getName().getName().equals("HashFragmentIndex"));
//java
Stream<FileBasedIndexExtension> javaIndices =
Stream<FileBasedIndexExtension<?, ?>> javaIndices =
FileBasedIndexExtension
.EXTENSION_POINT_NAME
.extensions()
@@ -202,11 +344,11 @@ public class DumpIndexAction extends AnAction {
return Stream.concat(Stream.concat(Stream.concat(coreIndices, javaIndices), xmlIndices), ktIndices);
}
private static final class IndexChunk {
public static final class IndexChunk {
private final Set<VirtualFile> myRoots;
private final String myName;
IndexChunk(Set<VirtualFile> roots, String name) {
public IndexChunk(Set<VirtualFile> roots, String name) {
myRoots = roots;
myName = name;
}
@@ -4,12 +4,10 @@ package com.intellij.util.indexing.hash;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.newvfs.persistent.ContentHashesUtil;
import com.intellij.psi.SingleRootFileViewProvider;
import com.intellij.util.indexing.*;
import com.intellij.util.indexing.impl.IndexStorage;
import com.intellij.util.indexing.impl.InputData;
import com.intellij.util.indexing.impl.MapIndexStorage;
import com.intellij.util.indexing.impl.MapReduceIndex;
@@ -18,35 +16,41 @@ import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class HashBasedIndexGenerator<K, V> {
@NotNull
private final File myOut;
@NotNull
private final FakeIndexExtension<K, V> myExtension;
@NotNull
private final FileBasedIndex.InputFilter myInputFilter;
private final Path myStorageFile;
private final AtomicInteger myIndexedFilesNumber = new AtomicInteger();
private final AtomicBoolean myIsEmpty = new AtomicBoolean(true);
private InvertedIndex<K, V, FileContent> myIndex;
public HashBasedIndexGenerator(@NotNull FileBasedIndexExtension<K, V> indexExtension, @NotNull File out) {
this(indexExtension.getKeyDescriptor(),
indexExtension.getValueExternalizer(),
indexExtension,
out
);
public HashBasedIndexGenerator(@NotNull FileBasedIndexExtension<K, V> indexExtension, @NotNull Path outRoot) {
this(indexExtension.getKeyDescriptor(), indexExtension.getValueExternalizer(), indexExtension, outRoot);
}
public HashBasedIndexGenerator(@NotNull KeyDescriptor<K> keyDescriptor,
@NotNull DataExternalizer<V> valueExternalizer,
@NotNull FileBasedIndexExtension<K, V> originalExtension,
@NotNull File out) {
@NotNull Path outRoot) {
myExtension = new FakeIndexExtension<>(keyDescriptor, valueExternalizer, originalExtension);
myOut = out;
String indexName = originalExtension.getName().getName();
myStorageFile = outRoot.resolve(StringUtil.toLowerCase(indexName)).resolve(indexName);
FileBasedIndex.InputFilter filter = originalExtension.getInputFilter();
@@ -54,33 +58,41 @@ public class HashBasedIndexGenerator<K, V> {
Set<FileType> fileTypes = new HashSet<>();
((FileBasedIndex.FileTypeSpecificInputFilter)filter).registerFileTypesUsedForIndexing(fileTypes::add);
myInputFilter = file -> fileTypes.contains(file.getFileType()) && filter.acceptInput(file);
} else {
}
else {
myInputFilter = filter;
}
}
@NotNull
public File getOut() {
return myOut;
}
public void openIndex() throws IOException {
String indexName = myExtension.getName().getName();
boolean singleEntry = myExtension.myOriginalExtension instanceof SingleEntryFileBasedIndexExtension;
myIndex = new MapReduceIndex<K, V, FileContent>(myExtension, new MapIndexStorage<K, V>(new File(new File(myOut, StringUtil.toLowerCase(indexName)), indexName).toPath(),
myExtension.getKeyDescriptor(),
myExtension.getValueExternalizer(),
myExtension.getCacheSize(),
myExtension.keyIsUniqueForIndexedFile()) {
IndexStorage<K, V> indexStorage = new MapIndexStorage<K, V>(myStorageFile,
myExtension.getKeyDescriptor(),
myExtension.getValueExternalizer(),
myExtension.getCacheSize(),
myExtension.keyIsUniqueForIndexedFile()) {
@Override
protected void checkCanceled() {
//ignore
}
}, null, null) {
@Override
public void addValue(K k, int inputId, V v) throws StorageException {
super.addValue(k, inputId, v);
myIsEmpty.set(false);
}
@Override
public void removeAllValues(@NotNull K k, int inputId) {
throw new AssertionError("Must not happen in index generator");
}
};
myIndex = new MapReduceIndex<K, V, FileContent>(myExtension, indexStorage, null, null) {
@NotNull
@Override
protected Map<K, V> mapByIndexer(int inputId, @NotNull FileContent content) {
Map<K, V> data = super.mapByIndexer(inputId, content);
boolean singleEntry = HashBasedIndexGenerator.this.myExtension.myOriginalExtension instanceof SingleEntryFileBasedIndexExtension;
if (singleEntry && !data.isEmpty()) {
data = Collections.singletonMap((K)(Integer)inputId, data.values().iterator().next());
}
@@ -105,7 +117,7 @@ public class HashBasedIndexGenerator<K, V> {
@Override
protected void requestRebuild(@NotNull Throwable e) {
throw new RuntimeException("error while processing " + indexName, e);
throw new RuntimeException("Error while processing " + myExtension.getName().getName(), e);
}
};
}
@@ -115,82 +127,47 @@ public class HashBasedIndexGenerator<K, V> {
}
public void closeIndex() throws IOException {
if (myIndex != null) myIndex.dispose();
if (myIndex != null) {
myIndex.dispose();
}
}
public static void generate(@NotNull Collection<VirtualFile> roots,
@NotNull Collection<HashBasedIndexGenerator<?, ?>> generators,
@NotNull Project project,
@NotNull File hashOut) {
LongAdder l = new LongAdder();
try {
ContentHashesUtil.HashEnumerator hashEnumerator = new ContentHashesUtil.HashEnumerator(new File(hashOut, "hashes").toPath());
for (HashBasedIndexGenerator<?, ?> generator : generators) {
generator.openIndex();
}
for (VirtualFile root : roots) {
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor<Boolean>() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory() && !SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
for (HashBasedIndexGenerator<?, ?> generator : generators) {
if (generator.myInputFilter.acceptInput(file)) {
l.increment();
generator.indexFile(file, project, hashEnumerator);
}
}
}
return true;
}
});
}
synchronized (hashEnumerator) {
hashEnumerator.close();
}
public void indexFile(@NotNull VirtualFile f, @NotNull Project project, @NotNull ContentHashesUtil.HashEnumerator hashEnumerator) {
if (!myInputFilter.acceptInput(f)) {
return;
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
try {
for (HashBasedIndexGenerator<?, ?> generator : generators) {
generator.closeIndex();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
System.out.println("Indexed " + l.sum() + " files to " + hashOut.getPath());
}
protected void indexFile(@NotNull VirtualFile f,
@NotNull Project project,
@NotNull ContentHashesUtil.HashEnumerator hashEnumerator) {
myIndexedFilesNumber.incrementAndGet();
try {
FileContentImpl fc = new FileContentImpl(f, f.contentsToByteArray());
byte[] hash = IndexedHashesSupport.getOrInitIndexedHash(fc, false);
int hashId;
synchronized (hashEnumerator) {
hashId = Math.abs(hashEnumerator.enumerate(hash));
}
int hashId = Math.abs(hashEnumerator.enumerate(hash));
fc.putUserData(IndexingDataKeys.PROJECT, project);
if (!myIndex.update(hashId, fc).compute()) {
throw new RuntimeException();
}
}
catch (IOException e) {
throw new RuntimeException("cant index " + f.getPath() + " for " + myExtension.getName().getName(), e);
throw new RuntimeException("Can't index " + f.getPath() + " for " + myExtension.getName().getName(), e);
}
}
@NotNull
public Path getIndexRoot() {
return myStorageFile.getParent();
}
public int getIndexedFilesNumber() {
return myIndexedFilesNumber.get();
}
public boolean isEmpty() {
return myIsEmpty.get();
}
public FileBasedIndexExtension<K, V> getExtension() {
return myExtension;
}
public InvertedIndex<K, V, FileContent> getIndex() {
return myIndex;
}
@@ -17,35 +17,44 @@ import com.intellij.util.indexing.impl.UpdateData;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class StubHashBasedIndexGenerator extends HashBasedIndexGenerator<Integer, SerializedStubTree> {
private final Map<StubIndexKey, HashBasedIndexGenerator> myStubIndexesGeneratorMap = new HashMap<>();
private final Set<StubIndexKey> myUsedKeys = new HashSet<>();
public StubHashBasedIndexGenerator(@NotNull File out) {
super(EnumeratorIntegerDescriptor.INSTANCE, new SerializedStubTreeDataExternalizer(
true,
null,
StubForwardIndexExternalizer.FileLocalStubForwardIndexExternalizer.INSTANCE), getExtension(), out);
private final Map<StubIndexKey<?, ?>, HashBasedIndexGenerator<?, ?>> myStubIndexesGeneratorMap = new HashMap<>();
private final Path myStubIndicesRoot;
public StubHashBasedIndexGenerator(@NotNull Path outRoot) {
super(
EnumeratorIntegerDescriptor.INSTANCE,
new SerializedStubTreeDataExternalizer(true, null, StubForwardIndexExternalizer.FileLocalStubForwardIndexExternalizer.INSTANCE),
new StubUpdatingIndex(StubForwardIndexExternalizer.FileLocalStubForwardIndexExternalizer.INSTANCE),
outRoot
);
myStubIndicesRoot = outRoot.resolve(StringUtil.toLowerCase(StubUpdatingIndex.INDEX_ID.getName()));
for (StubIndexExtension<?, ?> stubIndexExtension : StubIndexExtension.EP_NAME.getExtensionList()) {
FileBasedIndexExtension<?, Void> ex = StubIndexImpl
.wrapStubIndexExtension(stubIndexExtension);
myStubIndexesGeneratorMap.put(stubIndexExtension.getKey(), new HashBasedIndexGenerator(ex.getKeyDescriptor(),
ex.getValueExternalizer(),
ex,
new File(out, getStubsDir())
) {
});
FileBasedIndexExtension<?, Void> extension = StubIndexImpl.wrapStubIndexExtension(stubIndexExtension);
HashBasedIndexGenerator<?, Void> hashBasedIndexGenerator = createGenerator(extension);
myStubIndexesGeneratorMap.put(stubIndexExtension.getKey(), hashBasedIndexGenerator);
}
}
@NotNull
private static String getStubsDir() {
return StringUtil.toLowerCase(StubUpdatingIndex.INDEX_ID.getName());
private <K, V> HashBasedIndexGenerator<K, V> createGenerator(FileBasedIndexExtension<K, V> extension) {
return new HashBasedIndexGenerator<>(extension.getKeyDescriptor(), extension.getValueExternalizer(), extension, myStubIndicesRoot);
}
@NotNull
public List<HashBasedIndexGenerator<?, ?>> getStubGenerators() {
return new ArrayList<>(myStubIndexesGeneratorMap.values());
}
@Override
@@ -57,17 +66,23 @@ public class StubHashBasedIndexGenerator extends HashBasedIndexGenerator<Integer
for (Map.Entry<StubIndexKey, Map<Object, StubIdList>> entry : map.entrySet()) {
StubIndexKey key = entry.getKey();
Map<Object, StubIdList> value = entry.getValue();
myUsedKeys.add(key);
MapReduceIndex index = (MapReduceIndex)myStubIndexesGeneratorMap.get(key).getIndex();
Map<Object, Object> reducedValue = Maps.asMap(value.keySet(), k -> null);
index.updateWithMap(new UpdateData(hashId, reducedValue, () -> new EmptyInputDataDiffBuilder(hashId), index.getExtension().getName(), null));
UpdateData<?, ?> updateData = new UpdateData(
hashId,
reducedValue,
() -> new EmptyInputDataDiffBuilder(hashId),
index.getExtension().getName(),
null
);
index.updateWithMap(updateData);
}
}
@Override
public void openIndex() throws IOException {
super.openIndex();
for (HashBasedIndexGenerator generator : myStubIndexesGeneratorMap.values()) {
for (HashBasedIndexGenerator<?, ?> generator : myStubIndexesGeneratorMap.values()) {
generator.openIndex();
}
}
@@ -75,15 +90,11 @@ public class StubHashBasedIndexGenerator extends HashBasedIndexGenerator<Integer
@Override
public void closeIndex() throws IOException {
super.closeIndex();
for (Map.Entry<StubIndexKey, HashBasedIndexGenerator> entry : myStubIndexesGeneratorMap.entrySet()) {
HashBasedIndexGenerator generator = entry.getValue();
generator.closeIndex();
for (Map.Entry<StubIndexKey<?, ?>, HashBasedIndexGenerator<?, ?>> entry : myStubIndexesGeneratorMap.entrySet()) {
entry.getValue().closeIndex();
}
((SerializationManagerEx)SerializationManager.getInstance()).flushNameStorage();
FileUtil.copyDir(PathManager.getIndexRoot(), new File(getOut(), getStubsDir()), f -> f.getName().startsWith("rep.names"));
}
private static StubUpdatingIndex getExtension() {
return (new StubUpdatingIndex(StubForwardIndexExternalizer.FileLocalStubForwardIndexExternalizer.INSTANCE));
FileUtil.copyDir(PathManager.getIndexRoot(), myStubIndicesRoot.toFile(), f -> f.getName().startsWith("rep.names"));
}
}