Skip to content

Commit 1929824

Browse files
committed
fix multiple rescan requests and add ignoring events while rescan running.
1 parent 4964a61 commit 1929824

File tree

4 files changed

+148
-71
lines changed

4 files changed

+148
-71
lines changed

src/main/java/ai/deepcode/jbplugin/core/AnalysisData.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.intellij.openapi.progress.ProgressIndicator;
1313
import com.intellij.openapi.progress.ProgressManager;
1414
import com.intellij.openapi.project.Project;
15-
import com.intellij.openapi.project.ProjectManager;
1615
import com.intellij.openapi.util.TextRange;
1716
import com.intellij.psi.PsiFile;
1817
import org.jetbrains.annotations.NotNull;
@@ -130,17 +129,11 @@ static void removeFilesFromCache(@NotNull Collection<PsiFile> files) {
130129
}
131130
}
132131

133-
static void removeAllFilesFromCache(@NotNull Project project) {
134-
removeFilesFromCache(cachedFilesOfProject(project));
135-
}
136-
137132
static void removeProjectFromCache(@NotNull Project project) {
138-
// lets all running ProgressIndicators release MUTEX first
139-
RunUtils.cancelRunningIndicators(project);
140133
if (mapProject2BundleId.remove(project) != null) {
141134
info("Removed from cache: " + project);
142135
}
143-
removeAllFilesFromCache(project);
136+
removeFilesFromCache(cachedFilesOfProject(project));
144137
}
145138

146139
private static Collection<PsiFile> cachedFilesOfProject(@NotNull Project project) {
@@ -273,6 +266,10 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
273266
ProgressManager.checkCanceled();
274267
progress.setFraction(((double) fileCounter++) / totalFiles);
275268
progress.setText(PREPARE_FILES_TEXT + fileCounter + " of " + totalFiles + " files done.");
269+
if (!file.isValid()) {
270+
DCLogger.warn("Invalid PsiFile: " + psiFiles);
271+
continue;
272+
}
276273
final String path = DeepCodeUtils.getDeepCodedFilePath(file);
277274
// info("getHash requested");
278275
final String hash = getHash(file);
@@ -633,6 +630,8 @@ public static void clearCache(@Nullable final Project project) {
633630
final Set<Project> projects =
634631
(project == null) ? getAllCachedProject() : Collections.singleton(project);
635632
for (Project prj : projects) {
633+
// lets all running ProgressIndicators release MUTEX first
634+
RunUtils.cancelRunningIndicators(prj);
636635
removeProjectFromCache(prj);
637636
ServiceManager.getService(prj, myTodoView.class).refresh();
638637
mapProject2analysisUrl.put(prj, "");

src/main/java/ai/deepcode/jbplugin/core/MyBulkFileListener.java

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,8 @@ public void after(@NotNull List<? extends VFileEvent> events) {
5656
if (filesChangedOrCreated.size() > 10) {
5757
// if too many files changed then it's easier to do Bulk Mode full rescan
5858
RunUtils.setBulkMode(project);
59-
RunUtils.runInBackground(
60-
project,
61-
() -> {
62-
// small delay to prevent multiple rescan
63-
RunUtils.rescanProject(project, 100);
64-
/*
65-
AnalysisData.removeFilesFromCache(filesChangedOrCreated);
66-
RunUtils.updateCachedAnalysisResults(project, filesChangedOrCreated);
67-
*/
68-
RunUtils.unsetBulkMode(project);
69-
});
59+
// small delay to prevent multiple rescan Background tasks
60+
RunUtils.rescanInBackgroundCancellableDelayed(project, 100, true);
7061
} else {
7162
for (PsiFile psiFile : filesChangedOrCreated) {
7263
RunUtils.runInBackgroundCancellable(
@@ -89,14 +80,13 @@ public void after(@NotNull List<? extends VFileEvent> events) {
8980
VFileCreateEvent.class);
9081
if (!gcignoreChangedFiles.isEmpty()) {
9182
RunUtils.setBulkMode(project);
92-
RunUtils.runInBackground(
93-
project,
94-
() -> {
95-
gcignoreChangedFiles.forEach(DeepCodeIgnoreInfoHolder::update_dcignoreFileContent);
96-
// small delay to prevent multiple rescan
97-
RunUtils.rescanProject(project, 100);
98-
RunUtils.unsetBulkMode(project);
99-
});
83+
for (PsiFile gcignoreFile : gcignoreChangedFiles) {
84+
RunUtils.runInBackgroundCancellable(
85+
gcignoreFile,
86+
() -> DeepCodeIgnoreInfoHolder.update_dcignoreFileContent(gcignoreFile));
87+
}
88+
// small delay to prevent multiple rescan Background tasks
89+
RunUtils.rescanInBackgroundCancellableDelayed(project, 100, true);
10090
}
10191
}
10292
// fixme debug only
@@ -114,24 +104,18 @@ public void before(@NotNull List<? extends VFileEvent> events) {
114104
project, events, DeepCodeUtils::isSupportedFileFormat, VFileDeleteEvent.class);
115105
if (!filesRemoved.isEmpty()) {
116106
DCLogger.info("Found " + filesRemoved.size() + " files to remove: " + filesRemoved);
117-
RunUtils.setBulkMode(project);
107+
// if too many files removed then it's easier to do full rescan
118108
if (filesRemoved.size() > 10) {
119-
// if too many files removed then it's easier to do full rescan
120-
RunUtils.runInBackground(
121-
project,
122-
() -> {
123-
// small delay to prevent multiple rescan
124-
RunUtils.rescanProject(project, 100);
125-
RunUtils.unsetBulkMode(project);
126-
});
127-
} else {
109+
RunUtils.setBulkMode(project);
110+
// small delay to prevent multiple rescan Background tasks
111+
RunUtils.rescanInBackgroundCancellableDelayed(project, 100, true);
112+
} else if (!RunUtils.isFullRescanRequested(project)) {
128113
RunUtils.runInBackground(
129114
project,
130115
() -> {
131116
AnalysisData.removeFilesFromCache(filesRemoved);
132117
RunUtils.updateCachedAnalysisResults(
133118
project, Collections.emptyList(), filesRemoved);
134-
RunUtils.unsetBulkMode(project);
135119
});
136120
}
137121
}
@@ -141,14 +125,18 @@ public void before(@NotNull List<? extends VFileEvent> events) {
141125
project, events, DeepCodeIgnoreInfoHolder::is_ignoreFile, VFileDeleteEvent.class);
142126
if (!ignoreFilesToRemove.isEmpty()) {
143127
RunUtils.setBulkMode(project);
144-
RunUtils.runInBackground(
145-
project,
146-
() -> {
147-
ignoreFilesToRemove.forEach(DeepCodeIgnoreInfoHolder::remove_dcignoreFileContent);
148-
// small delay to prevent multiple rescan
149-
RunUtils.rescanProject(project, 100);
150-
RunUtils.unsetBulkMode(project);
151-
});
128+
// small delay to prevent multiple rescan Background tasks
129+
RunUtils.rescanInBackgroundCancellableDelayed(project, 100, true);
130+
/*
131+
RunUtils.rescanInBackgroundCancellableDelayed(
132+
project,
133+
100, // small delay to prevent multiple rescan
134+
() -> {
135+
ignoreFilesToRemove.forEach(DeepCodeIgnoreInfoHolder::remove_dcignoreFileContent);
136+
RunUtils.rescanProject(project);
137+
RunUtils.unsetBulkMode(project);
138+
});
139+
*/
152140
}
153141
}
154142
DCLogger.info("MyBulkFileListener.before ends");

src/main/java/ai/deepcode/jbplugin/core/MyProjectManagerListener.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ public void projectOpened(@NotNull Project project) {
3131

3232
@Override
3333
public void projectClosing(@NotNull Project project) {
34-
RunUtils.runInBackground(project, () -> AnalysisData.removeProjectFromCache(project));
34+
RunUtils.runInBackground(project, () -> {
35+
// lets all running ProgressIndicators release MUTEX first
36+
RunUtils.cancelRunningIndicators(project);
37+
AnalysisData.removeProjectFromCache(project);
38+
});
3539
}
3640

3741
private static class MyPsiTreeChangeAdapter extends PsiTreeChangeAdapter {
@@ -85,7 +89,7 @@ public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
8589
if (DeepCodeIgnoreInfoHolder.is_dcignoreFile(psiFile)) {
8690
DeepCodeIgnoreInfoHolder.update_dcignoreFileContent(psiFile);
8791
// delayed to prevent unnecessary updates in case of continuous typing by user
88-
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(project, 1000));
92+
RunUtils.rescanInBackgroundCancellableDelayed(project, 1000, false);
8993
}
9094
// .gitignore content delay to be parsed https://youtrack.jetbrains.com/issue/IDEA-239773
9195
final VirtualFile virtualFile = psiFile.getVirtualFile();
@@ -94,7 +98,7 @@ public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
9498
if (document != null) {
9599
FileDocumentManager.getInstance().saveDocument(document);
96100
// delayed to let git update it meta-info
97-
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(project, 1000));
101+
RunUtils.rescanInBackgroundCancellableDelayed(project, 1000, false);
98102
}
99103
}
100104
}
@@ -109,7 +113,7 @@ public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) {
109113
if (DeepCodeIgnoreInfoHolder.is_ignoreFile(psiFile)) {
110114
DeepCodeIgnoreInfoHolder.remove_dcignoreFileContent(psiFile);
111115
// ??? small delay to prevent duplicated delete with MyBulkFileListener
112-
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(psiFile.getProject(), 100));
116+
RunUtils.rescanInBackgroundCancellableDelayed(project, 100, false);
113117
}
114118
}
115119
}

src/main/java/ai/deepcode/jbplugin/core/RunUtils.java

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,6 @@ public static void delay(long millis) {
8585
ProgressManager.checkCanceled();
8686
}
8787

88-
private static long timeOfLastRescanRequest = 0;
89-
// BackgroundTaskQueue ??? com.intellij.openapi.wm.ex.StatusBarEx#getBackgroundProcesses ???
90-
public static void rescanProject(@NotNull Project project, long delayMilliseconds) {
91-
long timeOfThisRequest = timeOfLastRescanRequest = System.currentTimeMillis();
92-
DCLogger.info("Full rescan requested. Timestamp: " + timeOfThisRequest);
93-
delay(delayMilliseconds);
94-
if (timeOfLastRescanRequest > timeOfThisRequest) return;
95-
DCLogger.info("Full rescan PERFORMED with Timestamp: " + timeOfThisRequest);
96-
AnalysisData.removeAllFilesFromCache(project);
97-
// AnalysisData.clearCache(project);
98-
updateCachedAnalysisResults(project, null);
99-
}
100-
10188
public static void runInBackground(@NotNull Project project, @NotNull Runnable runnable) {
10289
DCLogger.info("runInBackground requested");
10390
final ProgressManager progressManager = ProgressManager.getInstance();
@@ -154,6 +141,7 @@ public static void cancelRunningIndicators(@NotNull Project project) {
154141
forceUnsetBulkMode(project);
155142
getRunningIndicators(project).forEach(ProgressIndicator::cancel);
156143
getRunningIndicators(project).clear();
144+
projectsWithFullRescanRequested.remove(project);
157145
}
158146

159147
private static final Map<VirtualFile, ProgressIndicator> mapFileProcessed2CancellableIndicator =
@@ -163,18 +151,20 @@ public static void cancelRunningIndicators(@NotNull Project project) {
163151

164152
public static void runInBackgroundCancellable(
165153
@NotNull PsiFile psiFile, @NotNull Runnable runnable) {
166-
final String runId = runnable.toString();
154+
final String s = runnable.toString();
155+
final String runId = s.substring(s.lastIndexOf('/'), s.length() - 1);
167156
DCLogger.info(
168157
"runInBackgroundCancellable requested for: "
169158
+ psiFile.getName()
170159
+ " with Runnable "
171-
+ runId.substring(runId.lastIndexOf('/'), runId.length() - 1));
160+
+ runId);
172161
final VirtualFile virtualFile = psiFile.getVirtualFile();
173162

174163
// To proceed multiple PSI events in a bunch (every 100 milliseconds)
175164
Runnable prevRunnable = mapFile2Runnable.put(virtualFile, runnable);
176165
if (prevRunnable != null) return;
177-
DCLogger.info("new Background task registered for: " + psiFile.getName());
166+
DCLogger.info(
167+
"new Background task registered for: " + psiFile.getName() + " with Runnable " + runId);
178168

179169
final Project project = psiFile.getProject();
180170
ProgressManager.getInstance()
@@ -206,12 +196,10 @@ && getRunningIndicators(project).contains(prevProgressIndicator)) {
206196

207197
Runnable actualRunnable = mapFile2Runnable.get(virtualFile);
208198
if (actualRunnable != null) {
209-
final String runId = actualRunnable.toString();
199+
final String s1 = actualRunnable.toString();
200+
final String runId = s1.substring(s1.lastIndexOf('/'), s1.length() - 1);
210201
DCLogger.info(
211-
"New Process started for "
212-
+ psiFile.getName()
213-
+ " with Runnable "
214-
+ runId.substring(runId.lastIndexOf('/'), runId.length() - 1));
202+
"New Process started for " + psiFile.getName() + " with Runnable " + runId);
215203
mapFile2Runnable.remove(virtualFile);
216204
actualRunnable.run();
217205
} else {
@@ -222,6 +210,104 @@ && getRunningIndicators(project).contains(prevProgressIndicator)) {
222210
});
223211
}
224212

213+
public static boolean isFullRescanRequested(@NotNull Project project) {
214+
return projectsWithFullRescanRequested.contains(project);
215+
}
216+
217+
private static final Set<Project> projectsWithFullRescanRequested =
218+
ContainerUtil.newConcurrentSet();
219+
220+
private static final Map<Project, ProgressIndicator> mapProject2CancellableIndicator =
221+
new ConcurrentHashMap<>();
222+
private static final Map<Project, Long> mapProject2CancellableRequestId =
223+
new ConcurrentHashMap<>();
224+
225+
private static final Map<Project, Long> mapProject2RequestId = new ConcurrentHashMap<>();
226+
private static final Set<Long> bulkModeRequests = ContainerUtil.newConcurrentSet();
227+
228+
public static void rescanInBackgroundCancellableDelayed(
229+
@NotNull Project project, long delayMilliseconds, boolean inBulkMode) {
230+
final long requestId = System.currentTimeMillis();
231+
DCLogger.info(
232+
"rescanInBackgroundCancellableDelayed requested for: "
233+
+ project.getName()
234+
+ "] with RequestId "
235+
+ requestId);
236+
projectsWithFullRescanRequested.add(project);
237+
238+
// To proceed multiple events in a bunch (every <delayMilliseconds>)
239+
Long prevRequestId = mapProject2RequestId.put(project, requestId);
240+
if (inBulkMode) bulkModeRequests.add(requestId);
241+
if (prevRequestId != null) {
242+
if (bulkModeRequests.remove(prevRequestId)) {
243+
RunUtils.unsetBulkMode(project);
244+
}
245+
return;
246+
}
247+
DCLogger.info(
248+
"new Background Rescan task registered for ["
249+
+ project.getName()
250+
+ "] with RequestId "
251+
+ requestId);
252+
253+
ProgressManager.getInstance()
254+
.run(
255+
new Task.Backgroundable(project, "DeepCode: Analysing Files...") {
256+
@Override
257+
public void run(@NotNull ProgressIndicator indicator) {
258+
259+
// To let new event cancel the currently running one
260+
ProgressIndicator prevProgressIndicator =
261+
mapProject2CancellableIndicator.put(project, indicator);
262+
if (prevProgressIndicator != null
263+
// can't use prevProgressIndicator.isRunning() due to
264+
// https://youtrack.jetbrains.com/issue/IDEA-241055
265+
&& getRunningIndicators(project).remove(prevProgressIndicator)) {
266+
DCLogger.info(
267+
"Previous Rescan cancelling for "
268+
+ project.getName()
269+
+ "\nProgressIndicator ["
270+
+ prevProgressIndicator.toString()
271+
+ "]");
272+
prevProgressIndicator.cancel();
273+
}
274+
getRunningIndicators(project).add(indicator);
275+
276+
// unset BulkMode if cancelled process did run under BulkMode
277+
Long prevRequestId = mapProject2CancellableRequestId.put(project, requestId);
278+
if (prevRequestId != null && bulkModeRequests.remove(prevRequestId)) {
279+
RunUtils.unsetBulkMode(project);
280+
}
281+
282+
// delay to let new consequent requests proceed and cancel current one
283+
// or to let Idea proceed internal events (.gitignore update)
284+
delay(delayMilliseconds);
285+
286+
Long actualRequestId = mapProject2RequestId.get(project);
287+
if (actualRequestId != null) {
288+
DCLogger.info(
289+
"New Rescan started for ["
290+
+ project.getName()
291+
+ "] with RequestId "
292+
+ actualRequestId);
293+
mapProject2RequestId.remove(project);
294+
295+
// actual rescan
296+
AnalysisData.removeProjectFromCache(project);
297+
updateCachedAnalysisResults(project, null);
298+
299+
if (bulkModeRequests.remove(actualRequestId)) {
300+
RunUtils.unsetBulkMode(project);
301+
}
302+
} else {
303+
DCLogger.warn("No actual RequestId found for: " + project.getName());
304+
}
305+
projectsWithFullRescanRequested.remove(project);
306+
DCLogger.info("Rescan ending for " + project.getName());
307+
}
308+
});
309+
}
310+
225311
public static void asyncAnalyseProjectAndUpdatePanel(@Nullable Project project) {
226312
final Project[] projects =
227313
(project == null)

0 commit comments

Comments
 (0)