import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.roots.FileIndexFacade;
-import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.util.Processor;
import com.intellij.util.SmartList;
import com.intellij.util.containers.CollectionFactory;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.text.StringSearcher;
-import gnu.trove.THashSet;
+import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
searchContext,
caseSensitively,
text,
- new CommonProcessors.CollectProcessor<VirtualFile>(result),
- progress
+ new CommonProcessors.CollectProcessor<VirtualFile>(result)
);
LOG.assertTrue(success);
return result;
}
public boolean processFilesWithText(@NotNull final GlobalSearchScope scope,
- final short searchContext,
- final boolean caseSensitively,
- @NotNull String text,
- @NotNull final Processor<VirtualFile> processor,
- @Nullable ProgressIndicator progress) {
- List<String> words = StringUtil.getWordsIn(text);
- if (words.isEmpty()) return true;
- Collections.sort(words, new Comparator<String>() {
+ final short searchContext,
+ final boolean caseSensitively,
+ @NotNull String text,
+ @NotNull final Processor<VirtualFile> processor) {
+ final ArrayList<IdIndexEntry> entries = getWordEntries(text, caseSensitively);
+ if (entries.isEmpty()) return true;
+
+ final Collection<VirtualFile> fileSet = ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() {
@Override
- public int compare(String o1, String o2) {
- return o2.length() - o1.length();
- }
- });
- final Set<VirtualFile> fileSet;
- CacheManager cacheManager = CacheManager.SERVICE.getInstance(myManager.getProject());
-
- if (words.size() > 1) {
- fileSet = new THashSet<VirtualFile>();
- Set<VirtualFile> copy = new THashSet<VirtualFile>();
- for (int i = 0; i < words.size() - 1; i++) {
- if (progress != null) {
- progress.checkCanceled();
- }
- else {
- ProgressManager.checkCanceled();
- }
- final String word = words.get(i);
- final int finalI = i;
- cacheManager.collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(i != 0 ? copy:fileSet) {
+ public Collection<VirtualFile> compute() {
+ final CommonProcessors.CollectProcessor<VirtualFile> collectProcessor = new CommonProcessors.CollectProcessor<VirtualFile>();
+ FileBasedIndex.getInstance().processFilesContainingAllKeys(IdIndex.NAME, entries, scope, new Condition<Integer>() {
@Override
- protected boolean accept(VirtualFile virtualFile) {
- return finalI == 0 || fileSet.contains(virtualFile);
+ public boolean value(Integer integer) {
+ return (integer.intValue() & searchContext) != 0;
}
- }, word, searchContext, scope, caseSensitively);
- if (i != 0) {
- fileSet.retainAll(copy);
- }
- copy.clear();
- if (fileSet.isEmpty()) break;
+ }, collectProcessor);
+ return collectProcessor.getResults();
}
- if (fileSet.isEmpty()) return true;
- }
- else {
- fileSet = null;
- }
+ });
- final String lastWord = words.get(words.size() - 1);
- if (processor instanceof CommonProcessors.CollectProcessor) {
- final CommonProcessors.CollectProcessor collectProcessor = (CommonProcessors.CollectProcessor)processor;
- return 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;
- }
- }, lastWord, searchContext, scope, caseSensitively);
- } 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;
+ final FileIndexFacade index = FileIndexFacade.getInstance(myManager.getProject());
+ return ContainerUtil.process(fileSet, new ReadActionProcessor<VirtualFile>() {
+ @Override
+ public boolean processInReadAction(VirtualFile virtualFile) {
+ return !IndexCacheManagerImpl.shouldBeFound(scope, virtualFile, index) || processor.process(virtualFile);
}
- return true;
- }
+ });
}
@Override
ProgressIndicator progress) {
final FileIndexFacade index = FileIndexFacade.getInstance(myManager.getProject());
final MultiMap<VirtualFile, RequestWithProcessor> result = createMultiMap();
- for (Set<IdIndexEntry> key : singles.keySet()) {
+ for (final Set<IdIndexEntry> key : singles.keySet()) {
if (key.isEmpty()) {
continue;
}
+
final Collection<RequestWithProcessor> data = singles.get(key);
- GlobalSearchScope commonScope = uniteScopes(data);
+ final GlobalSearchScope commonScope = uniteScopes(data);
- MultiMap<VirtualFile, RequestWithProcessor> intersection = null;
+ if (key.size() == 1) {
+ result.putAllValues(findFilesWithIndexEntry(key.iterator().next(), index, data, commonScope, progress));
+ continue;
+ }
- boolean first = true;
- for (IdIndexEntry entry : key) {
- final MultiMap<VirtualFile, RequestWithProcessor> local = findFilesWithIndexEntry(entry, index, data, commonScope, progress);
- if (first) {
- intersection = local;
- first = false;
+ final Collection<VirtualFile> fileSet = ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() {
+ @Override
+ public Collection<VirtualFile> compute() {
+ final CommonProcessors.CollectProcessor<VirtualFile> processor = new CommonProcessors.CollectProcessor<VirtualFile>();
+ FileBasedIndex.getInstance().processFilesContainingAllKeys(IdIndex.NAME, key, commonScope, null, processor);
+ return processor.getResults();
}
- else {
- intersection.keySet().retainAll(local.keySet());
- for (VirtualFile file : intersection.keySet()) {
- intersection.get(file).retainAll(local.get(file));
- }
+ });
+
+ for (final VirtualFile file : fileSet) {
+ if (progress != null) {
+ progress.checkCanceled();
+ }
+ for (final IdIndexEntry entry : key) {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, file, new FileBasedIndex.ValueProcessor<Integer>() {
+ @Override
+ public boolean process(VirtualFile file, Integer value) {
+ if (IndexCacheManagerImpl.shouldBeFound(commonScope, file, index)) {
+ int mask = value.intValue();
+ for (RequestWithProcessor single : data) {
+ final PsiSearchRequest request = single.request;
+ if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) {
+ result.putValue(file, single);
+ }
+ }
+ }
+ return true;
+ }
+ }, commonScope);
+
+ }
+ });
}
}
- result.putAllValues(intersection);
}
return result;
}
@Override
public SearchCostResult isCheapEnoughToSearch(@NotNull String name,
- @NotNull GlobalSearchScope scope,
+ @NotNull final GlobalSearchScope scope,
@Nullable final PsiFile fileToIgnoreOccurencesIn,
@Nullable ProgressIndicator progress) {
+
+ final ArrayList<IdIndexEntry> keys = getWordEntries(name, true);
+ if (keys.isEmpty()) return SearchCostResult.ZERO_OCCURRENCES;
+
+ final TIntHashSet set = ApplicationManager.getApplication().runReadAction(new NullableComputable<TIntHashSet>() {
+ @Override
+ public TIntHashSet compute() {
+ return FileBasedIndex.getInstance().collectFileIdsContainingAllKeys(IdIndex.NAME, keys, scope, null);
+ }
+ });
+
+ if (set == null || set.size() > 1000) {
+ return SearchCostResult.TOO_MANY_OCCURRENCES;
+ }
+
final AtomicInteger count = new AtomicInteger();
- if (!processFilesWithText(scope, UsageSearchContext.ANY, true, name, new CommonProcessors.CollectProcessor<VirtualFile> (Collections.<VirtualFile>emptyList()) {
+
+ final FileIndexFacade index = FileIndexFacade.getInstance(myManager.getProject());
+ final Processor<VirtualFile> processor = new Processor<VirtualFile>() {
private final VirtualFile fileToIgnoreOccurencesInVirtualFile =
- fileToIgnoreOccurencesIn != null ? fileToIgnoreOccurencesIn.getVirtualFile():null;
+ fileToIgnoreOccurencesIn != null ? fileToIgnoreOccurencesIn.getVirtualFile() : null;
@Override
public boolean process(VirtualFile file) {
if (file == fileToIgnoreOccurencesInVirtualFile) return true;
- int value = count.incrementAndGet();
+ if (!IndexCacheManagerImpl.shouldBeFound(scope, file, index)) return true;
+ final int value = count.incrementAndGet();
return value < 10;
}
- }, progress)) {
+ };
+ final boolean cheap = ApplicationManager.getApplication().runReadAction(new NullableComputable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ return FileBasedIndex.processVirtualFiles(set, scope, processor);
+ }
+ });
+
+ if (!cheap) {
return SearchCostResult.TOO_MANY_OCCURRENCES;
}
return count.get() == 0 ? SearchCostResult.ZERO_OCCURRENCES : SearchCostResult.FEW_OCCURRENCES;
}
+
+ private static ArrayList<IdIndexEntry> getWordEntries(String name, boolean caseSensitively) {
+ List<String> words = StringUtil.getWordsIn(name);
+ final ArrayList<IdIndexEntry> keys = new ArrayList<IdIndexEntry>();
+ for (String word : words) {
+ keys.add(new IdIndexEntry(word, caseSensitively));
+ }
+ return keys;
+ }
}
import com.intellij.psi.search.EverythingGlobalScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.SerializationManager;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.CommonProcessors;
-import com.intellij.util.Processor;
-import com.intellij.util.SmartList;
+import com.intellij.util.*;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ConcurrentHashSet;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBusConnection;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntIterator;
+import gnu.trove.TIntProcedure;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
}
-
- private <K, V> boolean processValuesImpl(final ID<K, V> indexId, final K dataKey, boolean ensureValueProcessedOnce,
- @Nullable final VirtualFile restrictToFile, ValueProcessor<V> processor,
- final GlobalSearchScope filter) {
+
+
+ private <K, V, R> R processExceptions(final ID<K, V> indexId,
+ @Nullable final VirtualFile restrictToFile,
+ final GlobalSearchScope filter,
+ ThrowableConvertor<UpdatableIndex<K, V, FileContent>, R, StorageException> computable) {
try {
final UpdatableIndex<K, V, FileContent> index = getIndex(indexId);
if (index == null) {
- return true;
+ return null;
}
final Project project = filter.getProject();
//assert project != null : "GlobalSearchScope#getProject() should be not-null for all index queries";
try {
index.getReadLock().lock();
+ return computable.convert(index);
+ }
+ finally {
+ index.getReadLock().unlock();
+ }
+ }
+ catch (StorageException e) {
+ scheduleRebuild(indexId, e);
+ }
+ catch (RuntimeException e) {
+ final Throwable cause = getCauseToRebuildIndex(e);
+ if (cause != null) {
+ scheduleRebuild(indexId, cause);
+ }
+ else {
+ throw e;
+ }
+ }
+ return null;
+ }
+
+ private <K, V> boolean processValuesImpl(final ID<K, V> indexId, final K dataKey, final boolean ensureValueProcessedOnce,
+ @Nullable final VirtualFile restrictToFile, final ValueProcessor<V> processor,
+ final GlobalSearchScope filter) {
+ ThrowableConvertor<UpdatableIndex<K, V, FileContent>, Boolean, StorageException> keyProcessor = new ThrowableConvertor<UpdatableIndex<K, V, FileContent>, Boolean, StorageException>() {
+ @Override
+ public Boolean convert(UpdatableIndex<K, V, FileContent> index) throws StorageException {
final ValueContainer<V> container = index.getData(dataKey);
boolean shouldContinue = true;
if (restrictToFile != null) {
if (restrictToFile instanceof VirtualFileWithId) {
final int restrictedFileId = getFileId(restrictToFile);
- for (final Iterator<V> valueIt = container.getValueIterator(); valueIt.hasNext();) {
+ for (final Iterator<V> valueIt = container.getValueIterator(); valueIt.hasNext(); ) {
final V value = valueIt.next();
if (container.isAssociated(value, restrictedFileId)) {
shouldContinue = processor.process(restrictToFile, value);
}
return shouldContinue;
}
- finally {
- index.getReadLock().unlock();
- }
- }
- catch (StorageException e) {
- scheduleRebuild(indexId, e);
- }
- catch (RuntimeException e) {
- final Throwable cause = getCauseToRebuildIndex(e);
- if (cause != null) {
- scheduleRebuild(indexId, cause);
- }
- else {
- throw e;
+ };
+ final Boolean result = processExceptions(indexId, restrictToFile, filter, keyProcessor);
+ return result == null || result.booleanValue();
+ }
+
+ public <K, V> void processFilesContainingAllKeys(final ID<K, V> indexId,
+ final Collection<K> dataKeys,
+ final GlobalSearchScope filter,
+ @Nullable Condition<V> valueChecker,
+ final Processor<VirtualFile> processor) {
+ final TIntHashSet set = collectFileIdsContainingAllKeys(indexId, dataKeys, filter, valueChecker);
+ if (set != null) {
+ processVirtualFiles(set, filter, processor);
+ }
+ }
+
+ @Nullable
+ public <K, V> TIntHashSet collectFileIdsContainingAllKeys(final ID<K, V> indexId,
+ final Collection<K> dataKeys,
+ final GlobalSearchScope filter,
+ @Nullable final Condition<V> valueChecker) {
+ final ThrowableConvertor<UpdatableIndex<K, V, FileContent>, TIntHashSet, StorageException> convertor =
+ new ThrowableConvertor<UpdatableIndex<K, V, FileContent>, TIntHashSet, StorageException>() {
+ @Nullable
+ @Override
+ public TIntHashSet convert(UpdatableIndex<K, V, FileContent> index) throws StorageException {
+ TIntHashSet mainIntersection = null;
+
+ for (K dataKey : dataKeys) {
+ ProgressManager.checkCanceled();
+ TIntHashSet copy = new TIntHashSet();
+ final ValueContainer<V> container = index.getData(dataKey);
+
+ for (final Iterator<V> valueIt = container.getValueIterator(); valueIt.hasNext(); ) {
+ final V value = valueIt.next();
+ if (valueChecker != null && !valueChecker.value(value)) {
+ continue;
+ }
+ for (final ValueContainer.IntIterator inputIdsIterator = container.getInputIdsIterator(value); inputIdsIterator.hasNext(); ) {
+ final int id = inputIdsIterator.next();
+ if (mainIntersection == null || mainIntersection.contains(id)) {
+ copy.add(id);
+ }
+ }
+ }
+
+ mainIntersection = copy;
+ if (mainIntersection.isEmpty()) {
+ return new TIntHashSet();
+ }
+ }
+
+ return mainIntersection;
+ }
+ };
+
+
+ return processExceptions(indexId, null, filter, convertor);
+ }
+
+ public static boolean processVirtualFiles(TIntHashSet ids, final GlobalSearchScope filter, final Processor<VirtualFile> processor) {
+ final PersistentFS fs = (PersistentFS)ManagingFS.getInstance();
+ return ids.forEach(new TIntProcedure() {
+ @Override
+ public boolean execute(int id) {
+ ProgressManager.checkCanceled();
+ VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id);
+ if (file != null && filter.accept(file)) {
+ return processor.process(file);
+ }
+ return true;
}
- }
- return true;
+ });
}
public static @Nullable Throwable getCauseToRebuildIndex(RuntimeException e) {