Skip to content

Commit 4964a61

Browse files
committed
fix cache invalidation in Bulk mode for files update
1 parent ea403ce commit 4964a61

File tree

4 files changed

+105
-87
lines changed

4 files changed

+105
-87
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ private AnalysisData() {}
4646

4747
// todo: keep few latest file versions (Guava com.google.common.cache.CacheBuilder ?)
4848
private static final Map<PsiFile, List<SuggestionForFile>> mapFile2Suggestions =
49-
// deepcode ignore ApiMigration~java.util.Hashtable: we need read and write full data lock
50-
new Hashtable<>(); // new ConcurrentHashMap<>();
49+
new ConcurrentHashMap<>();
5150

5251
private static final Map<PsiFile, String> mapPsiFile2Hash = new ConcurrentHashMap<>();
5352

@@ -111,6 +110,7 @@ static void removeFilesFromCache(@NotNull Collection<PsiFile> files) {
111110
info("Request to remove from cache " + files.size() + " files: " + files);
112111
// todo: do we really need mutex here?
113112
MUTEX.lock();
113+
info("MUTEX LOCK");
114114
int removeCounter = 0;
115115
for (PsiFile file : files) {
116116
if (file != null && isFileInCache(file)) {
@@ -125,6 +125,7 @@ static void removeFilesFromCache(@NotNull Collection<PsiFile> files) {
125125
+ " files. Were not in cache: "
126126
+ (files.size() - removeCounter));
127127
} finally {
128+
info("MUTEX RELEASED");
128129
MUTEX.unlock();
129130
}
130131
}
@@ -178,6 +179,7 @@ public static void updateCachedResultsForFiles(
178179
Collection<PsiFile> filesToProceed = null;
179180
try {
180181
MUTEX.lock();
182+
info("MUTEX LOCK");
181183
updateInProgress = true;
182184
filesToProceed =
183185
// DeepCodeUtils.computeNonBlockingReadAction(
@@ -213,7 +215,8 @@ public static void updateCachedResultsForFiles(
213215
updateInProgress = false;
214216

215217
} finally {
216-
if (filesToProceed != null && !filesToProceed.isEmpty()) info("MUTEX RELEASED");
218+
//if (filesToProceed != null && !filesToProceed.isEmpty())
219+
info("MUTEX RELEASED");
217220
MUTEX.unlock();
218221
}
219222
}
@@ -611,7 +614,7 @@ private static FileContent createFileContent(PsiFile psiFile) {
611614
public static Set<PsiFile> getAllFilesWithSuggestions(@NotNull final Project project) {
612615
return mapFile2Suggestions.entrySet().stream()
613616
.filter(e -> e.getKey().getProject().equals(project))
614-
// otherwise ai.deepcode.jbplugin.ui.TodoTreeBuilder.getAllFiles will fail
617+
// otherwise ai.deepcode.jbplugin.ui.TodoTreeBuilder.getAllFiles may fail
615618
.filter(e -> e.getKey().isValid())
616619
.filter(e -> !e.getValue().isEmpty())
617620
.map(Map.Entry::getKey)

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

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -26,58 +26,59 @@ public void after(@NotNull List<? extends VFileEvent> events) {
2626
// fixme debug only
2727
DCLogger.info("MyBulkFileListener.after begins for " + events.size() + " events " + events);
2828
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
29+
/*
30+
for (Project project : AnalysisData.getAllCachedProject()) {
31+
RunUtils.runInBackground(
32+
project,
33+
() -> {
34+
*/
35+
Set<PsiFile> filesChangedOrCreated =
36+
/*
37+
RunUtils.computeInReadActionInSmartMode(
38+
project,
39+
() ->
40+
*/
41+
getFilteredFilesByEventTypes(
42+
project,
43+
events,
44+
(psiFile -> DeepCodeUtils.isSupportedFileFormat(psiFile)
45+
// to prevent updating files already done by
46+
// MyPsiTreeChangeAdapter
47+
// fixme: doesn't work, try to use isFromSave or isFromRefresh
48+
// && AnalysisData.isHashChanged(psiFile)
49+
),
50+
VFileContentChangeEvent.class,
51+
VFileMoveEvent.class,
52+
VFileCopyEvent.class,
53+
VFileCreateEvent.class);
54+
if (!filesChangedOrCreated.isEmpty()) {
55+
DCLogger.info(filesChangedOrCreated.size() + " files changed: " + filesChangedOrCreated);
56+
if (filesChangedOrCreated.size() > 10) {
57+
// if too many files changed then it's easier to do Bulk Mode full rescan
58+
RunUtils.setBulkMode(project);
59+
RunUtils.runInBackground(
60+
project,
61+
() -> {
62+
// small delay to prevent multiple rescan
63+
RunUtils.rescanProject(project, 100);
2964
/*
30-
for (Project project : AnalysisData.getAllCachedProject()) {
31-
RunUtils.runInBackground(
32-
project,
33-
() -> {
34-
*/
35-
Set<PsiFile> filesChangedOrCreated =
36-
/*
37-
RunUtils.computeInReadActionInSmartMode(
38-
project,
39-
() ->
65+
AnalysisData.removeFilesFromCache(filesChangedOrCreated);
66+
RunUtils.updateCachedAnalysisResults(project, filesChangedOrCreated);
4067
*/
41-
getFilteredFilesByEventTypes(
42-
project,
43-
events,
44-
(psiFile ->
45-
DeepCodeUtils.isSupportedFileFormat(psiFile)
46-
// to prevent updating files already done by
47-
// MyPsiTreeChangeAdapter
48-
// fixme: doesn't work, try to use isFromSave or isFromRefresh
49-
//&& AnalysisData.isHashChanged(psiFile)
50-
),
51-
VFileContentChangeEvent.class,
52-
VFileMoveEvent.class,
53-
VFileCopyEvent.class,
54-
VFileCreateEvent.class);
55-
if (!filesChangedOrCreated.isEmpty()) {
56-
DCLogger.info(
57-
filesChangedOrCreated.size() + " files changed: " + filesChangedOrCreated);
58-
if (filesChangedOrCreated.size() > 10) {
59-
// if too many files changed then it's easier to do full rescan
60-
RunUtils.setBulkMode(project);
61-
RunUtils.runInBackground(
62-
project,
63-
() -> {
64-
AnalysisData.removeFilesFromCache(filesChangedOrCreated);
65-
RunUtils.updateCachedAnalysisResults(project, filesChangedOrCreated);
66-
RunUtils.unsetBulkMode(project);
67-
});
68-
} else {
69-
for (PsiFile psiFile : filesChangedOrCreated) {
70-
RunUtils.runInBackgroundCancellable(
71-
psiFile,
72-
() -> {
73-
AnalysisData.removeFilesFromCache(Collections.singleton(psiFile));
74-
RunUtils.updateCachedAnalysisResults(
75-
project, Collections.singleton(psiFile));
76-
});
77-
}
78-
}
79-
}
80-
// });
68+
RunUtils.unsetBulkMode(project);
69+
});
70+
} else {
71+
for (PsiFile psiFile : filesChangedOrCreated) {
72+
RunUtils.runInBackgroundCancellable(
73+
psiFile,
74+
() -> {
75+
AnalysisData.removeFilesFromCache(Collections.singleton(psiFile));
76+
RunUtils.updateCachedAnalysisResults(project, Collections.singleton(psiFile));
77+
});
78+
}
79+
}
80+
}
81+
// });
8182

8283
Set<PsiFile> gcignoreChangedFiles =
8384
getFilteredFilesByEventTypes(
@@ -92,8 +93,8 @@ public void after(@NotNull List<? extends VFileEvent> events) {
9293
project,
9394
() -> {
9495
gcignoreChangedFiles.forEach(DeepCodeIgnoreInfoHolder::update_dcignoreFileContent);
95-
// ??? small delay to prevent duplicated delete with MyPsiTreeChangeAdapter
96-
RunUtils.rescanProject(project, 0);
96+
// small delay to prevent multiple rescan
97+
RunUtils.rescanProject(project, 100);
9798
RunUtils.unsetBulkMode(project);
9899
});
99100
}
@@ -106,21 +107,33 @@ public void after(@NotNull List<? extends VFileEvent> events) {
106107
public void before(@NotNull List<? extends VFileEvent> events) {
107108
DCLogger.info("MyBulkFileListener.before begins for " + events.size() + " events " + events);
108109
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
109-
//for (Project project : AnalysisData.getAllCachedProject()) {
110+
// for (Project project : AnalysisData.getAllCachedProject()) {
110111
if (project.isDisposed()) continue;
111112
Set<PsiFile> filesRemoved =
112113
getFilteredFilesByEventTypes(
113114
project, events, DeepCodeUtils::isSupportedFileFormat, VFileDeleteEvent.class);
114115
if (!filesRemoved.isEmpty()) {
115116
DCLogger.info("Found " + filesRemoved.size() + " files to remove: " + filesRemoved);
116117
RunUtils.setBulkMode(project);
117-
RunUtils.runInBackground(
118-
project,
119-
() -> {
120-
AnalysisData.removeFilesFromCache(filesRemoved);
121-
RunUtils.updateCachedAnalysisResults(project, Collections.emptyList(), filesRemoved);
122-
RunUtils.unsetBulkMode(project);
123-
});
118+
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 {
128+
RunUtils.runInBackground(
129+
project,
130+
() -> {
131+
AnalysisData.removeFilesFromCache(filesRemoved);
132+
RunUtils.updateCachedAnalysisResults(
133+
project, Collections.emptyList(), filesRemoved);
134+
RunUtils.unsetBulkMode(project);
135+
});
136+
}
124137
}
125138

126139
Set<PsiFile> ignoreFilesToRemove =
@@ -132,8 +145,8 @@ public void before(@NotNull List<? extends VFileEvent> events) {
132145
project,
133146
() -> {
134147
ignoreFilesToRemove.forEach(DeepCodeIgnoreInfoHolder::remove_dcignoreFileContent);
135-
// ??? small delay to prevent duplicated delete with MyPsiTreeChangeAdapter
136-
RunUtils.rescanProject(project, 0);
148+
// small delay to prevent multiple rescan
149+
RunUtils.rescanProject(project, 100);
137150
RunUtils.unsetBulkMode(project);
138151
});
139152
}
@@ -148,6 +161,8 @@ private Set<PsiFile> getFilteredFilesByEventTypes(
148161
@NotNull Class<?>... classesOfEventsToFilter) {
149162
PsiManager manager = PsiManager.getInstance(project);
150163
return events.stream()
164+
// to prevent updating files already done by MyPsiTreeChangeAdapter
165+
.filter(VFileEvent::isFromRefresh)
151166
.filter(event -> PsiTreeUtil.instanceOf(event, classesOfEventsToFilter))
152167
.map(VFileEvent::getFile)
153168
.filter(Objects::nonNull)

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
6464
@Override
6565
public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
6666
final PsiFile psiFile = event.getFile();
67-
if (psiFile == null || RunUtils.inBulkMode(psiFile.getProject())) return;
67+
if (psiFile == null) return;
68+
final Project project = psiFile.getProject();
69+
if (RunUtils.inBulkMode(project)) return;
6870

6971
if (DeepCodeUtils.isSupportedFileFormat(psiFile)) {
7072
RunUtils.runInBackgroundCancellable(
@@ -76,14 +78,14 @@ public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
7678
// but in case of update finished between beforeChildrenChange and now.
7779
AnalysisData.removeFilesFromCache(psiFileSet);
7880
}
79-
RunUtils.updateCachedAnalysisResults(psiFile.getProject(), psiFileSet);
81+
RunUtils.updateCachedAnalysisResults(project, psiFileSet);
8082
});
8183
}
8284

8385
if (DeepCodeIgnoreInfoHolder.is_dcignoreFile(psiFile)) {
8486
DeepCodeIgnoreInfoHolder.update_dcignoreFileContent(psiFile);
8587
// delayed to prevent unnecessary updates in case of continuous typing by user
86-
RunUtils.rescanProject(psiFile.getProject(), 1000);
88+
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(project, 1000));
8789
}
8890
// .gitignore content delay to be parsed https://youtrack.jetbrains.com/issue/IDEA-239773
8991
final VirtualFile virtualFile = psiFile.getVirtualFile();
@@ -92,20 +94,22 @@ public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
9294
if (document != null) {
9395
FileDocumentManager.getInstance().saveDocument(document);
9496
// delayed to let git update it meta-info
95-
RunUtils.rescanProject(psiFile.getProject(), 1000);
97+
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(project, 1000));
9698
}
9799
}
98100
}
99101

100102
@Override
101103
public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) {
102104
PsiFile psiFile = (event.getChild() instanceof PsiFile) ? (PsiFile) event.getChild() : null;
103-
if (psiFile == null || RunUtils.inBulkMode(psiFile.getProject())) return;
105+
if (psiFile == null) return;
106+
final Project project = psiFile.getProject();
107+
if (RunUtils.inBulkMode(project)) return;
104108

105109
if (DeepCodeIgnoreInfoHolder.is_ignoreFile(psiFile)) {
106110
DeepCodeIgnoreInfoHolder.remove_dcignoreFileContent(psiFile);
107-
// small delay to prevent duplicated delete with MyBulkFileListener
108-
RunUtils.rescanProject(psiFile.getProject(), 100);
111+
// ??? small delay to prevent duplicated delete with MyBulkFileListener
112+
RunUtils.runInBackground(project, () -> RunUtils.rescanProject(psiFile.getProject(), 100));
109113
}
110114
}
111115
}

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

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ public static void unsetBulkMode(@NotNull Project project) {
5353
}
5454

5555
public static void forceUnsetBulkMode(@NotNull Project project) {
56-
mapProject2RequestsCounter.put(project, 0);
57-
DCLogger.info("BulkMode OFF forced");
56+
mapProject2RequestsCounter.put(project, 0);
57+
DCLogger.info("BulkMode OFF forced");
5858
}
5959

6060
public static void asyncUpdateCurrentFilePanel(PsiFile psiFile) {}
@@ -88,18 +88,14 @@ public static void delay(long millis) {
8888
private static long timeOfLastRescanRequest = 0;
8989
// BackgroundTaskQueue ??? com.intellij.openapi.wm.ex.StatusBarEx#getBackgroundProcesses ???
9090
public static void rescanProject(@NotNull Project project, long delayMilliseconds) {
91-
runInBackground(
92-
project,
93-
() -> {
94-
if (delayMilliseconds > 0) {
95-
long timeOfThisRequest = timeOfLastRescanRequest = System.currentTimeMillis();
96-
delay(delayMilliseconds);
97-
if (timeOfLastRescanRequest > timeOfThisRequest) return;
98-
}
99-
AnalysisData.removeAllFilesFromCache(project);
100-
// AnalysisData.clearCache(project);
101-
asyncAnalyseProjectAndUpdatePanel(project);
102-
});
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);
10399
}
104100

105101
public static void runInBackground(@NotNull Project project, @NotNull Runnable runnable) {

0 commit comments

Comments
 (0)