mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
file based index: do not completely rebuild indexes on file-type change, use indexed file type to invalidate indexes per file
GitOrigin-RevId: 73a2b9e2bc130c2af6c8d617d9fc62c9d68f07ad
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d153a0e89a
commit
5f197fe078
@@ -47,21 +47,7 @@ public final class FileTypeIndexImpl
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
int version = 2;
|
||||
|
||||
if (!InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED) {
|
||||
FileType[] types = FileTypeRegistry.getInstance().getRegisteredFileTypes();
|
||||
for (FileType type : types) {
|
||||
version += type.getName().hashCode();
|
||||
}
|
||||
|
||||
version *= 31;
|
||||
for (FileTypeRegistry.FileTypeDetector detector : FileTypeRegistry.FileTypeDetector.EP_NAME.getExtensionList()) {
|
||||
version += detector.getVersion();
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -17,7 +17,6 @@ import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
class FileTypeKeyDescriptor implements KeyDescriptor<FileType> {
|
||||
private static final FileType OUT_DATED_FILE_TYPE = new OutDatedFileType();
|
||||
static final FileTypeKeyDescriptor INSTANCE = new FileTypeKeyDescriptor();
|
||||
|
||||
@Override
|
||||
@@ -29,6 +28,9 @@ class FileTypeKeyDescriptor implements KeyDescriptor<FileType> {
|
||||
public boolean isEqual(FileType val1, FileType val2) {
|
||||
if (val1 instanceof SubstitutedFileType) val1 = ((SubstitutedFileType)val1).getFileType();
|
||||
if (val2 instanceof SubstitutedFileType) val2 = ((SubstitutedFileType)val2).getFileType();
|
||||
if (val1 instanceof OutDatedFileType || val2 instanceof OutDatedFileType) {
|
||||
return Comparing.equal(val1.getName(), val2.getName());
|
||||
}
|
||||
return Comparing.equal(val1, val2);
|
||||
}
|
||||
|
||||
@@ -41,14 +43,19 @@ class FileTypeKeyDescriptor implements KeyDescriptor<FileType> {
|
||||
public FileType read(@NotNull DataInput in) throws IOException {
|
||||
String read = EnumeratorStringDescriptor.INSTANCE.read(in);
|
||||
FileType fileType = FileTypeRegistry.getInstance().findFileTypeByName(read);
|
||||
return fileType == null ? OUT_DATED_FILE_TYPE : fileType;
|
||||
return fileType == null ? new OutDatedFileType(read) : fileType;
|
||||
}
|
||||
|
||||
private static class OutDatedFileType implements FileType {
|
||||
@NotNull
|
||||
private final String myName;
|
||||
|
||||
private OutDatedFileType(@NotNull String name) {myName = name;}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
return myName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -23,17 +23,14 @@ class FileTypeMapReduceIndex extends VfsAwareMapReduceIndex<FileType, Void, File
|
||||
@Override
|
||||
public boolean isIndexedStateForFile(int fileId, @NotNull IndexedFile file) {
|
||||
boolean isIndexed = super.isIndexedStateForFile(fileId, file);
|
||||
if (!InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED) return isIndexed;
|
||||
if (isIndexed) {
|
||||
try {
|
||||
Map<FileType, Void> inputData = ((MapInputDataDiffBuilder<FileType, Void>) getKeysDiffBuilder(fileId)). getMap();
|
||||
FileType indexedFileType = ContainerUtil.getFirstItem(inputData.keySet());
|
||||
// can be null if file type name is outdated
|
||||
return FileTypeKeyDescriptor.INSTANCE.isEqual(indexedFileType, file.getFileType());
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
if (!isIndexed) return false;
|
||||
try {
|
||||
Map<FileType, Void> inputData = ((MapInputDataDiffBuilder<FileType, Void>) getKeysDiffBuilder(fileId)). getMap();
|
||||
FileType indexedFileType = ContainerUtil.getFirstItem(inputData.keySet());
|
||||
return FileTypeKeyDescriptor.INSTANCE.isEqual(indexedFileType, file.getFileType());
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
return false;
|
||||
}
|
||||
return isIndexed;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-73
@@ -2,88 +2,22 @@
|
||||
package com.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.fileTypes.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.*;
|
||||
|
||||
class FileBasedIndexFileTypeListener implements FileTypeListener {
|
||||
@Nullable private Map<FileType, Set<String>> myTypeToExtensionMap;
|
||||
|
||||
@Override
|
||||
public void beforeFileTypesChanged(@NotNull final FileTypeEvent event) {
|
||||
FileBasedIndexImpl.cleanupProcessedFlag();
|
||||
myTypeToExtensionMap = new THashMap<>();
|
||||
FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
for (FileType type : fileTypeManager.getRegisteredFileTypes()) {
|
||||
myTypeToExtensionMap.put(type, getExtensions(type, fileTypeManager));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileTypesChanged(@NotNull final FileTypeEvent event) {
|
||||
final Map<FileType, Set<String>> oldTypeToExtensionsMap = myTypeToExtensionMap;
|
||||
myTypeToExtensionMap = null;
|
||||
|
||||
// file type added
|
||||
FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance();
|
||||
if (event.getAddedFileType() != null) {
|
||||
fileBasedIndex.rebuildAllIndices("The following file type was added: " + event.getAddedFileType());
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldTypeToExtensionsMap == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<FileType, Set<String>> newTypeToExtensionsMap = new THashMap<>();
|
||||
FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
for (FileType type : fileTypeManager.getRegisteredFileTypes()) {
|
||||
newTypeToExtensionsMap.put(type, getExtensions(type, fileTypeManager));
|
||||
}
|
||||
// file type changes and removals
|
||||
if (!newTypeToExtensionsMap.keySet().containsAll(oldTypeToExtensionsMap.keySet())) {
|
||||
Set<FileType> removedFileTypes = new HashSet<>(oldTypeToExtensionsMap.keySet());
|
||||
removedFileTypes.removeAll(newTypeToExtensionsMap.keySet());
|
||||
fileBasedIndex
|
||||
.rebuildAllIndices("The following file types were removed/are no longer associated: " + removedFileTypes);
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<FileType, Set<String>> entry : oldTypeToExtensionsMap.entrySet()) {
|
||||
FileType fileType = entry.getKey();
|
||||
Set<String> oldMatchers = entry.getValue();
|
||||
Set<String> newMatchers = newTypeToExtensionsMap.get(fileType);
|
||||
if (!newMatchers.equals(oldMatchers)) {
|
||||
Set<String> removed = complement(oldMatchers, newMatchers);
|
||||
Set<String> added = complement(newMatchers, oldMatchers);
|
||||
fileBasedIndex.rebuildAllIndices(fileType.getName()
|
||||
+ " is no longer associated with matchers "
|
||||
+ String.join(",", removed)
|
||||
+ ", added matchers "
|
||||
+ String.join(",", added));
|
||||
return;
|
||||
Set<ID<?, ?>> indexesToRebuild = new THashSet<>();
|
||||
for (FileBasedIndexExtension<?, ?> extension : FileBasedIndexExtension.EXTENSION_POINT_NAME.getExtensionList()) {
|
||||
if (IndexingStamp.versionDiffers(extension.getName(), extension.getVersion())) {
|
||||
indexesToRebuild.add(extension.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getExtensions(@NotNull FileType type, @NotNull FileTypeManager fileTypeManager) {
|
||||
return fileTypeManager
|
||||
.getAssociations(type)
|
||||
.stream()
|
||||
.map(FileNameMatcher::getPresentableString)
|
||||
.collect(Collectors.toCollection(THashSet::new));
|
||||
}
|
||||
|
||||
private static Set<String> complement(Set<String> set, Set<String> toRemove) {
|
||||
THashSet<String> result = new THashSet<>(set);
|
||||
result.removeAll(toRemove);
|
||||
return result;
|
||||
FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance();
|
||||
fileBasedIndex.scheduleFullIndexesRescan(indexesToRebuild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,15 +29,12 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.roots.CollectingContentIterator;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdaterImpl;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.AsyncFileListener;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.openapi.vfs.newvfs.AsyncEventSupport;
|
||||
@@ -57,7 +54,6 @@ import com.intellij.psi.impl.PsiManagerImpl;
|
||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
|
||||
import com.intellij.psi.impl.cache.impl.id.PlatformIdTableBuilding;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.search.FileTypeIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.SerializationManagerEx;
|
||||
import com.intellij.util.*;
|
||||
@@ -213,19 +209,13 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
initComponent();
|
||||
}
|
||||
|
||||
void rebuildAllIndices(@NotNull String reason) {
|
||||
doClearIndices(id -> {
|
||||
if (!InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED) return true;
|
||||
|
||||
if (id.equals(FileTypeIndex.NAME)) return false;
|
||||
|
||||
if (getState().getIndex(id).getExtension().getIndexer() instanceof CompositeDataIndexer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
scheduleIndexRebuild("File type change" + ", " + reason);
|
||||
void scheduleFullIndexesRescan(@NotNull Collection<ID<?, ?>> indexesToRebuild) {
|
||||
cleanupProcessedFlag();
|
||||
doClearIndices(id -> indexesToRebuild.contains(id));
|
||||
String rebuiltIndexesLog = indexesToRebuild.isEmpty()
|
||||
? ""
|
||||
: "; indexes \" + indexesToRebuild + \" will be rebuild completely due to version change\" ";
|
||||
scheduleIndexRebuild("File type change" + rebuiltIndexesLog);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -1247,7 +1237,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<ID<?, ?>> getAffectedIndexCandidates(@NotNull VirtualFile file) {
|
||||
List<ID<?, ?>> getAffectedIndexCandidates(@NotNull VirtualFile file) {
|
||||
if (file.isDirectory()) {
|
||||
return isProjectOrWorkspaceFile(file, null) ? Collections.emptyList() : myRegisteredIndexes.getIndicesForDirectories();
|
||||
}
|
||||
@@ -1271,7 +1261,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
fc.putUserData(IndexingDataKeys.PROJECT, project);
|
||||
}
|
||||
|
||||
private boolean updateSingleIndex(@NotNull ID<?, ?> indexId, @Nullable VirtualFile file, int inputId, @Nullable FileContent currentFC) {
|
||||
boolean updateSingleIndex(@NotNull ID<?, ?> indexId, @Nullable VirtualFile file, int inputId, @Nullable FileContent currentFC) {
|
||||
if (!myRegisteredIndexes.isExtensionsDataLoaded()) reportUnexpectedAsyncInitState();
|
||||
if (!RebuildStatus.isOk(indexId) && !myIsUnitTestMode) {
|
||||
return false; // the index is scheduled for rebuild, no need to update
|
||||
@@ -1380,7 +1370,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsFileContentLoading(@NotNull ID<?, ?> indexId) {
|
||||
boolean needsFileContentLoading(@NotNull ID<?, ?> indexId) {
|
||||
return !myRegisteredIndexes.isNotRequiringContentIndex(indexId);
|
||||
}
|
||||
|
||||
@@ -1458,7 +1448,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
|
||||
if (!contentChange) {
|
||||
FileContent fileContent = null;
|
||||
for (ID<?, ?> indexId : fileIsDirectory ? myRegisteredIndexes.getIndicesForDirectories() : myRegisteredIndexes.getNotRequiringContentIndices()) {
|
||||
for (ID<?, ?> indexId : getContentLessIndexes(fileIsDirectory)) {
|
||||
if (getInputFilter(indexId).acceptInput(file)) {
|
||||
if (fileContent == null) {
|
||||
fileContent = new FileContentImpl(file);
|
||||
@@ -1507,7 +1497,12 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
}
|
||||
}
|
||||
|
||||
private static FileTypeManagerImpl getFileTypeManager() {
|
||||
@NotNull
|
||||
Collection<ID<?, ?>> getContentLessIndexes(boolean isDirectory) {
|
||||
return isDirectory ? myRegisteredIndexes.getIndicesForDirectories() : myRegisteredIndexes.getNotRequiringContentIndices();
|
||||
}
|
||||
|
||||
static FileTypeManagerImpl getFileTypeManager() {
|
||||
return (FileTypeManagerImpl)FileTypeManager.getInstance();
|
||||
}
|
||||
|
||||
@@ -1756,110 +1751,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
return file instanceof VirtualFileWithId ?((VirtualFileWithId)file).getId() : IndexingStamp.INVALID_FILE_ID;
|
||||
}
|
||||
|
||||
private class UnindexedFilesFinder implements CollectingContentIterator {
|
||||
private final List<VirtualFile> myFiles = new ArrayList<>();
|
||||
private final Project myProject;
|
||||
private final boolean myDoTraceForFilesToBeIndexed = LOG.isTraceEnabled();
|
||||
|
||||
UnindexedFilesFinder(@NotNull Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<VirtualFile> getFiles() {
|
||||
List<VirtualFile> files;
|
||||
synchronized (myFiles) {
|
||||
files = myFiles;
|
||||
}
|
||||
|
||||
// When processing roots concurrently myFiles looses the local order of local vs archive files
|
||||
// If we process the roots in 2 threads we can just separate local vs archive
|
||||
// IMPORTANT: also remove duplicated file that can appear due to roots intersection
|
||||
BitSet usedFileIds = new BitSet(files.size());
|
||||
List<VirtualFile> localFileSystemFiles = new ArrayList<>(files.size() / 2);
|
||||
List<VirtualFile> archiveFiles = new ArrayList<>(files.size() / 2);
|
||||
|
||||
for(VirtualFile file:files) {
|
||||
int fileId = ((VirtualFileWithId)file).getId();
|
||||
if (usedFileIds.get(fileId)) continue;
|
||||
usedFileIds.set(fileId);
|
||||
|
||||
if (file.getFileSystem() instanceof LocalFileSystem) localFileSystemFiles.add(file);
|
||||
else archiveFiles.add(file);
|
||||
}
|
||||
|
||||
localFileSystemFiles.addAll(archiveFiles);
|
||||
return localFileSystemFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processFile(@NotNull final VirtualFile file) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (!file.isValid()) {
|
||||
return true;
|
||||
}
|
||||
if (file instanceof VirtualFileSystemEntry && ((VirtualFileSystemEntry)file).isFileIndexed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(file instanceof VirtualFileWithId)) {
|
||||
return true;
|
||||
}
|
||||
getFileTypeManager().freezeFileTypeTemporarilyIn(file, () -> {
|
||||
IndexedFile fileContent = new IndexedFileImpl(file, myProject);
|
||||
|
||||
boolean isUptoDate = true;
|
||||
boolean isDirectory = file.isDirectory();
|
||||
if (!isDirectory && !isTooLarge(file)) {
|
||||
final List<ID<?, ?>> affectedIndexCandidates = getAffectedIndexCandidates(file);
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0, size = affectedIndexCandidates.size(); i < size; ++i) {
|
||||
final ID<?, ?> indexId = affectedIndexCandidates.get(i);
|
||||
try {
|
||||
if (needsFileContentLoading(indexId) && shouldIndexFile(fileContent, indexId)) {
|
||||
if (myDoTraceForFilesToBeIndexed) {
|
||||
LOG.trace("Scheduling indexing of " + file + " by request of index " + indexId);
|
||||
}
|
||||
synchronized (myFiles) {
|
||||
myFiles.add(file);
|
||||
}
|
||||
isUptoDate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
if (cause instanceof IOException || cause instanceof StorageException) {
|
||||
LOG.info(e);
|
||||
requestRebuild(indexId);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int inputId = Math.abs(getIdMaskingNonIdBasedFile(file));
|
||||
for (ID<?, ?> indexId : isDirectory ? myRegisteredIndexes.getIndicesForDirectories() : myRegisteredIndexes.getNotRequiringContentIndices()) {
|
||||
if (shouldIndexFile(fileContent, indexId)) {
|
||||
updateSingleIndex(indexId, file, inputId, new IndexedFileWrapper(fileContent));
|
||||
}
|
||||
}
|
||||
IndexingStamp.flushCache(inputId);
|
||||
|
||||
if (isUptoDate && file instanceof VirtualFileSystemEntry) {
|
||||
((VirtualFileSystemEntry)file).setFileIndexed(true);
|
||||
}
|
||||
});
|
||||
|
||||
ProgressManager.checkCanceled();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldIndexFile(@NotNull IndexedFile file, @NotNull ID<?, ?> indexId) {
|
||||
boolean shouldIndexFile(@NotNull IndexedFile file, @NotNull ID<?, ?> indexId) {
|
||||
VirtualFile virtualFile = file.getFile();
|
||||
return getInputFilter(indexId).acceptInput(virtualFile) &&
|
||||
(isMock(virtualFile) || !getIndex(indexId).isIndexedStateForFile(((NewVirtualFile) virtualFile).getId(), file));
|
||||
@@ -1869,7 +1761,7 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
return !(file instanceof NewVirtualFile);
|
||||
}
|
||||
|
||||
private boolean isTooLarge(@NotNull VirtualFile file) {
|
||||
boolean isTooLarge(@NotNull VirtualFile file) {
|
||||
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
|
||||
return !myRegisteredIndexes.skipLimitCheck(file) || SingleRootFileViewProvider.isTooLargeForContentLoading(file);
|
||||
}
|
||||
@@ -1883,11 +1775,6 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
CollectingContentIterator createContentIterator(@NotNull Project project) {
|
||||
return new UnindexedFilesFinder(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexableSet(@NotNull IndexableFileSet set, @Nullable Project project) {
|
||||
myIndexableSets.add(set);
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
// 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.util.indexing;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.CollectingContentIterator;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
|
||||
import com.intellij.psi.search.FileTypeIndex;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class UnindexedFilesFinder implements CollectingContentIterator {
|
||||
private static final Logger LOG = Logger.getInstance(UnindexedFilesFinder.class);
|
||||
|
||||
private final List<VirtualFile> myFiles = new ArrayList<>();
|
||||
private final Project myProject;
|
||||
private final boolean myDoTraceForFilesToBeIndexed = FileBasedIndexImpl.LOG.isTraceEnabled();
|
||||
private final FileBasedIndexImpl myFileBasedIndex;
|
||||
|
||||
UnindexedFilesFinder(@NotNull Project project) {
|
||||
myProject = project;
|
||||
myFileBasedIndex = ((FileBasedIndexImpl)FileBasedIndex.getInstance());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<VirtualFile> getFiles() {
|
||||
List<VirtualFile> files;
|
||||
synchronized (myFiles) {
|
||||
files = myFiles;
|
||||
}
|
||||
|
||||
// When processing roots concurrently myFiles looses the local order of local vs archive files
|
||||
// If we process the roots in 2 threads we can just separate local vs archive
|
||||
// IMPORTANT: also remove duplicated file that can appear due to roots intersection
|
||||
BitSet usedFileIds = new BitSet(files.size());
|
||||
List<VirtualFile> localFileSystemFiles = new ArrayList<>(files.size() / 2);
|
||||
List<VirtualFile> archiveFiles = new ArrayList<>(files.size() / 2);
|
||||
|
||||
for(VirtualFile file:files) {
|
||||
int fileId = ((VirtualFileWithId)file).getId();
|
||||
if (usedFileIds.get(fileId)) continue;
|
||||
usedFileIds.set(fileId);
|
||||
|
||||
if (file.getFileSystem() instanceof LocalFileSystem) localFileSystemFiles.add(file);
|
||||
else archiveFiles.add(file);
|
||||
}
|
||||
|
||||
localFileSystemFiles.addAll(archiveFiles);
|
||||
return localFileSystemFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processFile(@NotNull final VirtualFile file) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (!file.isValid()) {
|
||||
return true;
|
||||
}
|
||||
if (file instanceof VirtualFileSystemEntry && ((VirtualFileSystemEntry)file).isFileIndexed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(file instanceof VirtualFileWithId)) {
|
||||
return true;
|
||||
}
|
||||
FileBasedIndexImpl.getFileTypeManager().freezeFileTypeTemporarilyIn(file, () -> {
|
||||
IndexedFile fileContent = new IndexedFileImpl(file, myProject);
|
||||
|
||||
boolean isUptoDate = true;
|
||||
boolean isDirectory = file.isDirectory();
|
||||
int inputId = Math.abs(FileBasedIndexImpl.getIdMaskingNonIdBasedFile(file));
|
||||
if (!isDirectory && !myFileBasedIndex.isTooLarge(file)) {
|
||||
|
||||
if (!isIndexedFileTypeUpToDate(fileContent, inputId)) {
|
||||
for (ID<?, ?> state : IndexingStamp.getNontrivialFileIndexedStates(inputId)) {
|
||||
myFileBasedIndex.getIndex(state).resetIndexedStateForFile(inputId);
|
||||
}
|
||||
synchronized (myFiles) {
|
||||
myFiles.add(file);
|
||||
}
|
||||
isUptoDate = false;
|
||||
}
|
||||
|
||||
if (isUptoDate) {
|
||||
final List<ID<?, ?>> affectedIndexCandidates = myFileBasedIndex.getAffectedIndexCandidates(file);
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0, size = affectedIndexCandidates.size(); i < size; ++i) {
|
||||
final ID<?, ?> indexId = affectedIndexCandidates.get(i);
|
||||
try {
|
||||
if (myFileBasedIndex.needsFileContentLoading(indexId) && myFileBasedIndex.shouldIndexFile(fileContent, indexId)) {
|
||||
if (myDoTraceForFilesToBeIndexed) {
|
||||
LOG.trace("Scheduling indexing of " + file + " by request of index " + indexId);
|
||||
}
|
||||
synchronized (myFiles) {
|
||||
myFiles.add(file);
|
||||
}
|
||||
isUptoDate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
if (cause instanceof IOException || cause instanceof StorageException) {
|
||||
LOG.info(e);
|
||||
myFileBasedIndex.requestRebuild(indexId);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ID<?, ?> indexId : myFileBasedIndex.getContentLessIndexes(isDirectory)) {
|
||||
if (myFileBasedIndex.shouldIndexFile(fileContent, indexId)) {
|
||||
myFileBasedIndex.updateSingleIndex(indexId, file, inputId, new IndexedFileWrapper(fileContent));
|
||||
}
|
||||
}
|
||||
IndexingStamp.flushCache(inputId);
|
||||
|
||||
if (isUptoDate && file instanceof VirtualFileSystemEntry) {
|
||||
((VirtualFileSystemEntry)file).setFileIndexed(true);
|
||||
}
|
||||
});
|
||||
|
||||
ProgressManager.checkCanceled();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isIndexedFileTypeUpToDate(@NotNull IndexedFile file, int inputId) {
|
||||
long stamp = IndexingStamp.getIndexStamp(inputId, FileTypeIndex.NAME);
|
||||
long fileTypeIndexVersion = IndexingStamp.getIndexCreationStamp(FileTypeIndex.NAME);
|
||||
if (stamp != fileTypeIndexVersion) return false;
|
||||
|
||||
FileType actualFileType = file.getFileType();
|
||||
try {
|
||||
Map<FileType, Void> indexedFileType = myFileBasedIndex.getIndex(FileTypeIndex.NAME).getIndexedFileData(inputId);
|
||||
return actualFileType.equals(ContainerUtil.getFirstItem(indexedFileType.keySet()));
|
||||
}
|
||||
catch (StorageException e) {
|
||||
myFileBasedIndex.requestRebuild(FileTypeIndex.NAME, e);
|
||||
LOG.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public final class UnindexedFilesUpdater extends DumbModeTask {
|
||||
|
||||
myIndex.clearIndicesIfNecessary();
|
||||
|
||||
CollectingContentIterator finder = myIndex.createContentIterator(myProject);
|
||||
CollectingContentIterator finder = new UnindexedFilesFinder(myProject);
|
||||
snapshot = PerformanceWatcher.takeSnapshot();
|
||||
|
||||
myIndex.iterateIndexableFilesConcurrently(finder, myProject, indicator);
|
||||
|
||||
@@ -21,19 +21,21 @@ public class FileTypeIndexTest extends BasePlatformTestCase {
|
||||
|
||||
public void testAddFileType() {
|
||||
FileTypeIndexImpl index = FileBasedIndexExtension.EXTENSION_POINT_NAME.findExtension(FileTypeIndexImpl.class);
|
||||
myFixture.configureByText("foo.test", "abc");
|
||||
VirtualFile file = myFixture.configureByText("foo.test", "abc").getVirtualFile();
|
||||
FileTypeIndex.getFiles(PlainTextFileType.INSTANCE, GlobalSearchScope.allScope(getProject()));
|
||||
|
||||
FileType foo = registerFakeFileType();
|
||||
int version = index.getVersion();
|
||||
FileType foo = registerFakeFileType();
|
||||
try {
|
||||
assertSame(!InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED,version == index.getVersion());
|
||||
assertEquals(version, index.getVersion());
|
||||
Collection<VirtualFile> files = FileTypeIndex.getFiles(foo, GlobalSearchScope.allScope(getProject()));
|
||||
assertEquals(1, files.size());
|
||||
assertOneElement(files);
|
||||
assertEquals(foo, FileTypeIndex.getIndexedFileType(file, getProject()));
|
||||
}
|
||||
finally {
|
||||
FileTypeManagerEx.getInstanceEx().unregisterFileType(foo);
|
||||
}
|
||||
assertEquals(PlainTextFileType.INSTANCE, FileTypeIndex.getIndexedFileType(file, getProject()));
|
||||
assertEmpty(FileTypeIndex.getFiles(foo, GlobalSearchScope.allScope(getProject())));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user