mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
isCheap calculation should NOT be costly!
This commit is contained in:
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.IndexPattern;
|
||||
import com.intellij.psi.search.IndexPatternProvider;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -40,6 +41,12 @@ public interface CacheManager {
|
||||
|
||||
boolean processFilesWithWord(@NotNull Processor<PsiFile> processor,@NotNull String word, short occurenceMask, @NotNull GlobalSearchScope scope, final boolean caseSensitively);
|
||||
|
||||
// IMPORTANT!!!
|
||||
// Do not call indices directly or indirectly from 'process' method, deadlocks are possible (IDEADEV-42137).
|
||||
public void collectVirtualFilesWithWord(@NotNull final CommonProcessors.CollectProcessor<VirtualFile> fileProcessor,
|
||||
@NotNull final String word, final short occurrenceMask,
|
||||
@NotNull final GlobalSearchScope scope, final boolean caseSensitively);
|
||||
|
||||
/**
|
||||
* @return all VirtualFile's that contain todo-items under project roots
|
||||
*/
|
||||
|
||||
+20
-14
@@ -45,9 +45,7 @@ import com.intellij.util.indexing.FileBasedIndex;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -78,44 +76,52 @@ public class IndexCacheManagerImpl implements CacheManager{
|
||||
return (scope.isSearchOutsideRootModel() || index.isInContent(virtualFile) || index.isInLibrarySource(virtualFile)) && !virtualFile.getFileType().isBinary();
|
||||
}
|
||||
|
||||
// IMPORTANT!!!
|
||||
// Since implementation of virtualFileProcessor.process() may call indices directly or indirectly,
|
||||
// we cannot call it inside FileBasedIndex.processValues() method except in collecting form
|
||||
// If we do, deadlocks are possible (IDEADEV-42137). Process the files without not holding indices' read lock.
|
||||
@Override
|
||||
public boolean processFilesWithWord(@NotNull final Processor<PsiFile> psiFileProcessor, @NotNull final String word, final short occurrenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
|
||||
public void collectVirtualFilesWithWord(@NotNull final CommonProcessors.CollectProcessor<VirtualFile> fileProcessor,
|
||||
@NotNull final String word, final short occurrenceMask,
|
||||
@NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
|
||||
if (myProject.isDefault()) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
final Set<VirtualFile> vFiles = new THashSet<VirtualFile>();
|
||||
final GlobalSearchScope projectScope = GlobalSearchScope.allScope(myProject).union(scope);
|
||||
|
||||
try {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileBasedIndex.getInstance().processValues(IdIndex.NAME, new IdIndexEntry(word, caseSensitively), null, new FileBasedIndex.ValueProcessor<Integer>() {
|
||||
final FileIndexFacade index = FileIndexFacade.getInstance(myProject);
|
||||
@Override
|
||||
public boolean process(final VirtualFile file, final Integer value) {
|
||||
ProgressManager.checkCanceled();
|
||||
final int mask = value.intValue();
|
||||
if ((mask & occurrenceMask) != 0) {
|
||||
vFiles.add(file);
|
||||
if ((mask & occurrenceMask) != 0 && scope.contains(file) && shouldBeFound(scope, file, index)) {
|
||||
if (!fileProcessor.process(file)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, projectScope);
|
||||
}, GlobalSearchScope.allScope(myProject).union(scope));
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IndexNotReadyException e) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processFilesWithWord(@NotNull final Processor<PsiFile> psiFileProcessor, @NotNull final String word, final short occurrenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
|
||||
final List<VirtualFile> vFiles = new ArrayList<VirtualFile>(5);
|
||||
collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(vFiles), word, occurrenceMask, scope, caseSensitively);
|
||||
if (vFiles.isEmpty()) return true;
|
||||
|
||||
final FileIndexFacade index = FileIndexFacade.getInstance(myProject);
|
||||
|
||||
final Processor<VirtualFile> virtualFileProcessor = new ReadActionProcessor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean processInReadAction(VirtualFile virtualFile) {
|
||||
LOG.assertTrue(virtualFile.isValid());
|
||||
if (virtualFile.isValid() && scope.contains(virtualFile) && shouldBeFound(scope, virtualFile, index)) {
|
||||
if (virtualFile.isValid()) {
|
||||
final PsiFile psiFile = myPsiManager.findFile(virtualFile);
|
||||
return psiFile == null || psiFileProcessor.process(psiFile);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.concurrency.JobUtil;
|
||||
import com.intellij.ide.todo.TodoIndexPatternProvider;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
@@ -346,13 +347,14 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
myManager.startBatchFilesProcessingMode();
|
||||
try {
|
||||
final List<VirtualFile> result = new ArrayList<VirtualFile>();
|
||||
boolean success = processFilesWithText(scope, searchContext, caseSensitively, text, new Processor<PsiFile>() {
|
||||
@Override
|
||||
public boolean process(PsiFile file) {
|
||||
result.add(file.getViewProvider().getVirtualFile());
|
||||
return true;
|
||||
}
|
||||
}, progress);
|
||||
boolean success = processFilesWithText(
|
||||
scope,
|
||||
searchContext,
|
||||
caseSensitively,
|
||||
text,
|
||||
new CommonProcessors.CollectProcessor<VirtualFile>(result),
|
||||
progress
|
||||
);
|
||||
LOG.assertTrue(success);
|
||||
return result;
|
||||
}
|
||||
@@ -365,7 +367,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
final short searchContext,
|
||||
final boolean caseSensitively,
|
||||
@NotNull String text,
|
||||
@NotNull final Processor<PsiFile> processor,
|
||||
@NotNull final Processor<VirtualFile> processor,
|
||||
@Nullable ProgressIndicator progress) {
|
||||
List<String> words = StringUtil.getWordsIn(text);
|
||||
if (words.isEmpty()) return true;
|
||||
@@ -375,10 +377,12 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
return o2.length() - o1.length();
|
||||
}
|
||||
});
|
||||
final Set<PsiFile> fileSet;
|
||||
final Set<VirtualFile> fileSet;
|
||||
CacheManager cacheManager = CacheManager.SERVICE.getInstance(myManager.getProject());
|
||||
|
||||
if (words.size() > 1) {
|
||||
fileSet = new THashSet<PsiFile>();
|
||||
Set<PsiFile> copy = new THashSet<PsiFile>();
|
||||
fileSet = new THashSet<VirtualFile>();
|
||||
Set<VirtualFile> copy = new THashSet<VirtualFile>();
|
||||
for (int i = 0; i < words.size() - 1; i++) {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
@@ -387,11 +391,14 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
ProgressManager.checkCanceled();
|
||||
}
|
||||
final String word = words.get(i);
|
||||
CacheManager.SERVICE.getInstance(myManager.getProject()).processFilesWithWord(new CommonProcessors.CollectProcessor<PsiFile>(copy), word, searchContext, scope, caseSensitively);
|
||||
if (i == 0) {
|
||||
fileSet.addAll(copy);
|
||||
}
|
||||
else {
|
||||
final int finalI = i;
|
||||
cacheManager.collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(i != 0 ? copy:fileSet) {
|
||||
@Override
|
||||
protected boolean accept(VirtualFile virtualFile) {
|
||||
return finalI == 0 || fileSet.contains(virtualFile);
|
||||
}
|
||||
}, word, searchContext, scope, caseSensitively);
|
||||
if (i != 0) {
|
||||
fileSet.retainAll(copy);
|
||||
}
|
||||
copy.clear();
|
||||
@@ -402,15 +409,37 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
else {
|
||||
fileSet = null;
|
||||
}
|
||||
return CacheManager.SERVICE.getInstance(myManager.getProject()).processFilesWithWord(new Processor<PsiFile>() {
|
||||
@Override
|
||||
public boolean process(PsiFile psiFile) {
|
||||
if (fileSet != null && !fileSet.contains(psiFile)) {
|
||||
|
||||
final String lastWord = words.get(words.size() - 1);
|
||||
if (processor instanceof CommonProcessors.CollectProcessor) {
|
||||
final CommonProcessors.CollectProcessor collectProcessor = (CommonProcessors.CollectProcessor)processor;
|
||||
cacheManager.collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(collectProcessor.getResults()) {
|
||||
@Override
|
||||
public boolean process(VirtualFile virtualFile) {
|
||||
if (fileSet == null || fileSet.contains(virtualFile)) return collectProcessor.process(virtualFile);
|
||||
return true;
|
||||
}
|
||||
return processor.process(psiFile);
|
||||
}, lastWord, searchContext, scope, caseSensitively);
|
||||
return true;
|
||||
} else {
|
||||
THashSet<VirtualFile> files = new THashSet<VirtualFile>();
|
||||
cacheManager.collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(files) {
|
||||
@Override
|
||||
protected boolean accept(VirtualFile virtualFile) {
|
||||
return fileSet == null || fileSet.contains(virtualFile);
|
||||
}
|
||||
}, lastWord, searchContext, scope, caseSensitively);
|
||||
ReadActionProcessor<VirtualFile> readActionProcessor = new ReadActionProcessor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean processInReadAction(VirtualFile virtualFile) {
|
||||
return processor.process(virtualFile);
|
||||
}
|
||||
};
|
||||
for(VirtualFile file:files) {
|
||||
if (!readActionProcessor.process(file)) return false;
|
||||
}
|
||||
}, words.get(words.size() - 1), searchContext, scope, caseSensitively);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -828,22 +857,21 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
@NotNull GlobalSearchScope scope,
|
||||
@Nullable final PsiFile fileToIgnoreOccurencesIn,
|
||||
@Nullable ProgressIndicator progress) {
|
||||
final int[] count = {0};
|
||||
if (!processFilesWithText(scope, UsageSearchContext.ANY, true, name, new Processor<PsiFile>() {
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
if (!processFilesWithText(scope, UsageSearchContext.ANY, true, name, new CommonProcessors.CollectProcessor<VirtualFile> (Collections.<VirtualFile>emptyList()) {
|
||||
private final VirtualFile fileToIgnoreOccurencesInVirtualFile =
|
||||
fileToIgnoreOccurencesIn != null ? fileToIgnoreOccurencesIn.getVirtualFile():null;
|
||||
|
||||
@Override
|
||||
public boolean process(PsiFile file) {
|
||||
if (file == fileToIgnoreOccurencesIn) return true;
|
||||
synchronized (count) {
|
||||
count[0]++;
|
||||
return count[0] <= 10;
|
||||
}
|
||||
public boolean process(VirtualFile file) {
|
||||
if (file == fileToIgnoreOccurencesInVirtualFile) return true;
|
||||
int value = count.incrementAndGet();
|
||||
return value < 10;
|
||||
}
|
||||
}, progress)) {
|
||||
return SearchCostResult.TOO_MANY_OCCURRENCES;
|
||||
}
|
||||
|
||||
synchronized (count) {
|
||||
return count[0] == 0 ? SearchCostResult.ZERO_OCCURRENCES : SearchCostResult.FEW_OCCURRENCES;
|
||||
}
|
||||
return count.get() == 0 ? SearchCostResult.ZERO_OCCURRENCES : SearchCostResult.FEW_OCCURRENCES;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user