Move shouldBeFound method to FileIndexFacade
[idea/community.git] / platform / lang-impl / src / com / intellij / psi / impl / cache / impl / IndexCacheManagerImpl.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.psi.impl.cache.impl;
18
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.application.ReadActionProcessor;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.progress.ProcessCanceledException;
23 import com.intellij.openapi.progress.ProgressManager;
24 import com.intellij.openapi.project.IndexNotReadyException;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.roots.FileIndexFacade;
27 import com.intellij.openapi.util.Computable;
28 import com.intellij.openapi.vfs.VirtualFile;
29 import com.intellij.psi.PsiFile;
30 import com.intellij.psi.PsiManager;
31 import com.intellij.psi.impl.cache.CacheManager;
32 import com.intellij.psi.impl.cache.impl.id.IdIndex;
33 import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
34 import com.intellij.psi.search.GlobalSearchScope;
35 import com.intellij.util.CommonProcessors;
36 import com.intellij.util.Processor;
37 import com.intellij.util.indexing.FileBasedIndex;
38 import org.jetbrains.annotations.NotNull;
39
40 import java.util.ArrayList;
41 import java.util.List;
42
43 /**
44  * @author Eugene Zhuravlev
45  *         Date: Jan 16, 2008
46  */
47 public class IndexCacheManagerImpl implements CacheManager{
48   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.cache.impl.IndexCacheManagerImpl");
49   private final Project myProject;
50   private final PsiManager myPsiManager;
51
52   public IndexCacheManagerImpl(PsiManager psiManager) {
53     myPsiManager = psiManager;
54     myProject = psiManager.getProject();
55   }
56
57   @Override
58   @NotNull
59   public PsiFile[] getFilesWithWord(@NotNull final String word, final short occurenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
60     if (myProject.isDefault()) {
61       return PsiFile.EMPTY_ARRAY;
62     }
63     CommonProcessors.CollectProcessor<PsiFile> processor = new CommonProcessors.CollectProcessor<PsiFile>();
64     processFilesWithWord(processor, word, occurenceMask, scope, caseSensitively);
65     return processor.getResults().isEmpty() ? PsiFile.EMPTY_ARRAY : processor.toArray(PsiFile.EMPTY_ARRAY);
66   }
67
68   // IMPORTANT!!!
69   // Since implementation of virtualFileProcessor.process() may call indices directly or indirectly,
70   // we cannot call it inside FileBasedIndex.processValues() method except in collecting form
71   // If we do, deadlocks are possible (IDEADEV-42137). Process the files without not holding indices' read lock.
72   private boolean collectVirtualFilesWithWord(@NotNull final Processor<VirtualFile> fileProcessor,
73                                              @NotNull final String word, final short occurrenceMask,
74                                              @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
75     if (myProject.isDefault()) {
76       return true;
77     }
78
79     try {
80       return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
81         @Override
82         public Boolean compute() {
83           return FileBasedIndex.getInstance().processValues(IdIndex.NAME, new IdIndexEntry(word, caseSensitively), null, new FileBasedIndex.ValueProcessor<Integer>() {
84             final FileIndexFacade index = FileIndexFacade.getInstance(myProject);
85             @Override
86             public boolean process(final VirtualFile file, final Integer value) {
87               ProgressManager.checkCanceled();
88               final int mask = value.intValue();
89               if ((mask & occurrenceMask) != 0 && index.shouldBeFound(scope, file)) {
90                 if (!fileProcessor.process(file)) return false;
91               }
92               return true;
93             }
94           }, scope);
95         }
96       });
97     }
98     catch (IndexNotReadyException e) {
99       throw new ProcessCanceledException();
100     }
101   }
102
103   @Override
104   public boolean processFilesWithWord(@NotNull final Processor<PsiFile> psiFileProcessor, @NotNull final String word, final short occurrenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
105     final List<VirtualFile> vFiles = new ArrayList<VirtualFile>(5);
106     collectVirtualFilesWithWord(new CommonProcessors.CollectProcessor<VirtualFile>(vFiles), word, occurrenceMask, scope, caseSensitively);
107     if (vFiles.isEmpty()) return true;
108
109     final Processor<VirtualFile> virtualFileProcessor = new ReadActionProcessor<VirtualFile>() {
110       @Override
111       public boolean processInReadAction(VirtualFile virtualFile) {
112         if (virtualFile.isValid()) {
113           final PsiFile psiFile = myPsiManager.findFile(virtualFile);
114           return psiFile == null || psiFileProcessor.process(psiFile);
115         }
116         return true;
117       }
118     };
119
120
121     // IMPORTANT!!!
122     // Since implementation of virtualFileProcessor.process() may call indices directly or indirectly,
123     // we cannot call it inside FileBasedIndex.processValues() method
124     // If we do, deadlocks are possible (IDEADEV-42137). So first we obtain files with the word specified,
125     // and then process them not holding indices' read lock.
126     for (VirtualFile vFile : vFiles) {
127       ProgressManager.checkCanceled();
128       if (!virtualFileProcessor.process(vFile)) {
129         return false;
130       }
131     }
132     return true;
133   }
134 }