Skip to content

Commit f7af528

Browse files
committed
speedup suggestion's highlighting for large projects by "pre-fetching" analysis results for changed file before full bundle update/extend;
deep refactoring for analysis logic.
1 parent 705eb94 commit f7af528

File tree

2 files changed

+135
-52
lines changed

2 files changed

+135
-52
lines changed

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

Lines changed: 132 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package ai.deepcode.jbplugin.core;
22

33
import ai.deepcode.javaclient.DeepCodeRestApi;
4-
import ai.deepcode.javaclient.requests.ExtendBundleRequest;
5-
import ai.deepcode.javaclient.requests.FileContent;
6-
import ai.deepcode.javaclient.requests.FileHash2ContentRequest;
7-
import ai.deepcode.javaclient.requests.FileHashRequest;
4+
import ai.deepcode.javaclient.requests.*;
85
import ai.deepcode.javaclient.responses.*;
96
import ai.deepcode.jbplugin.ui.myTodoView;
107
import com.intellij.openapi.components.ServiceManager;
@@ -164,33 +161,42 @@ public static void updateCachedResultsForFiles(
164161
return;
165162
}
166163
info("Update requested for " + psiFiles.size() + " files: " + psiFiles.toString());
167-
Collection<PsiFile> filesToProceed = null;
168164
try {
169165
MUTEX.lock();
170166
info("MUTEX LOCK");
171167
updateInProgress = true;
172-
filesToProceed =
173-
// DeepCodeUtils.computeNonBlockingReadAction(
174-
// () ->
168+
Collection<PsiFile> filesToProceed =
175169
psiFiles.stream()
176170
.filter(Objects::nonNull)
177-
// .filter(PsiFile::isValid)
178171
.filter(file -> !mapFile2Suggestions.containsKey(file))
179172
.collect(Collectors.toSet());
180173
if (!filesToProceed.isEmpty()) {
181-
// deepcode ignore checkIsPresent~Optional: collection already checked to be not empty
182-
final PsiFile firstFile = filesToProceed.stream().findFirst().get();
174+
// collection already checked to be not empty
175+
final PsiFile firstFile = filesToProceed.iterator().next();
176+
final String fileHash = HashContentUtils.getHash(firstFile);
183177
info(
184178
"Files to proceed (not found in cache): "
185179
+ filesToProceed.size()
186180
// fixme debug only
187181
+ "\nHash for first file "
188182
+ firstFile.getName()
189183
+ " ["
190-
+ HashContentUtils.getHash(firstFile)
184+
+ fileHash
191185
+ "]");
192186

193-
mapFile2Suggestions.putAll(retrieveSuggestions(project, filesToProceed, filesToRemove));
187+
if (filesToProceed.size() == 1 && filesToRemove.isEmpty()) {
188+
// if only one file updates then its most likely from annotator. So we need to get
189+
// suggestions asap:
190+
// we do that through createBundle with fileContent
191+
mapFile2Suggestions.put(firstFile, retrieveSuggestions(firstFile));
192+
// and then request normal extendBundle later to synchronize results on server
193+
RunUtils.runInBackgroundCancellable(
194+
firstFile,
195+
() -> retrieveSuggestions(project, filesToProceed, filesToRemove));
196+
} else {
197+
198+
mapFile2Suggestions.putAll(retrieveSuggestions(project, filesToProceed, filesToRemove));
199+
}
194200

195201
} else if (!filesToRemove.isEmpty()) {
196202
info("Files to remove: " + filesToRemove.size() + " files: " + filesToRemove.toString());
@@ -238,14 +244,38 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
238244
}
239245
// no needs to check login here as it will be checked anyway during every api response's check
240246
// if (!LoginUtils.isLogged(project, false)) return EMPTY_MAP;
241-
Map<PsiFile, List<SuggestionForFile>> result;
247+
248+
List<String> missingFiles = createBundleStep(project, filesToProceed, filesToRemove);
249+
250+
uploadFilesStep(project, filesToProceed, missingFiles);
251+
252+
// ---------------------------------------- Get Analysis
242253
ProgressIndicator progress =
243254
ProgressManager.getInstance().getProgressIndicator(); // new StatusBarProgress();
244-
progress.setIndeterminate(false);
255+
final String bundleId = mapProject2BundleId.getOrDefault(project, "");
256+
if (bundleId.isEmpty()) return EMPTY_MAP; // no sense to proceed without bundleId
257+
long startTime = System.currentTimeMillis();
258+
progress.setText(WAITING_FOR_ANALYSIS_TEXT);
259+
ProgressManager.checkCanceled();
260+
GetAnalysisResponse getAnalysisResponse = doGetAnalysis(project, bundleId, progress);
261+
Map<PsiFile, List<SuggestionForFile>> result =
262+
parseGetAnalysisResponse(project, filesToProceed, getAnalysisResponse);
263+
info("--- Get Analysis took: " + (System.currentTimeMillis() - startTime) + " milliseconds");
264+
return result;
265+
}
245266

246-
long startTime;
247-
// ---------------------------------------- Create Bundle
248-
startTime = System.currentTimeMillis();
267+
/**
268+
* Perform costly network request. <b>No cache checks!</b>
269+
*
270+
* @return missingFiles
271+
*/
272+
private static List<String> createBundleStep(
273+
@NotNull Project project,
274+
@NotNull Collection<PsiFile> filesToProceed,
275+
@NotNull Collection<PsiFile> filesToRemove) {
276+
ProgressIndicator progress =
277+
ProgressManager.getInstance().getProgressIndicator(); // new StatusBarProgress();
278+
long startTime = System.currentTimeMillis();
249279
progress.setText(PREPARE_FILES_TEXT);
250280
info(PREPARE_FILES_TEXT);
251281
ProgressManager.checkCanceled();
@@ -276,7 +306,6 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
276306
CreateBundleResponse createBundleResponse = makeNewBundle(project, mapPath2Hash, filesToRemove);
277307

278308
final String bundleId = createBundleResponse.getBundleId();
279-
if (bundleId.isEmpty()) return EMPTY_MAP; // no sense to proceed without bundleId
280309

281310
List<String> missingFiles = createBundleResponse.getMissingFiles();
282311
info(
@@ -287,36 +316,90 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
287316
+ bundleId
288317
+ "\nmissingFiles: "
289318
+ missingFiles.size());
319+
return missingFiles;
320+
}
290321

291-
// ---------------------------------------- Upload Files
292-
startTime = System.currentTimeMillis();
322+
/** Perform costly network request. <b>No cache checks!</b> */
323+
private static void uploadFilesStep(
324+
@NotNull Project project,
325+
@NotNull Collection<PsiFile> filesToProceed,
326+
@NotNull List<String> missingFiles) {
327+
ProgressIndicator progress =
328+
ProgressManager.getInstance().getProgressIndicator(); // new StatusBarProgress();
329+
long startTime = System.currentTimeMillis();
293330
progress.setText(UPLOADING_FILES_TEXT);
294331
ProgressManager.checkCanceled();
295332

296-
final int attempts = 5;
297-
for (int counter = 0; counter < attempts; counter++) {
298-
uploadFiles(project, filesToProceed, missingFiles, bundleId, progress);
299-
missingFiles = checkBundle(project, bundleId, progress);
300-
if (missingFiles.isEmpty()) {
301-
break;
302-
} else {
303-
warn(
304-
"Check Bundle found some missingFiles to be NOT uploaded, will try to upload "
305-
+ (attempts - counter)
306-
+ " more times:\nmissingFiles = "
307-
+ missingFiles);
333+
final String bundleId = mapProject2BundleId.getOrDefault(project, "");
334+
if (bundleId.isEmpty()) {
335+
info("BundleId is empty");
336+
} else if (missingFiles.isEmpty()) {
337+
info("No missingFiles to Upload");
338+
} else {
339+
final int attempts = 5;
340+
for (int counter = 0; counter < attempts; counter++) {
341+
uploadFiles(project, filesToProceed, missingFiles, bundleId, progress);
342+
missingFiles = checkBundle(project, bundleId, progress);
343+
if (missingFiles.isEmpty()) {
344+
break;
345+
} else {
346+
warn(
347+
"Check Bundle found some missingFiles to be NOT uploaded, will try to upload "
348+
+ (attempts - counter)
349+
+ " more times:\nmissingFiles = "
350+
+ missingFiles);
351+
}
308352
}
309353
}
310-
// mapPsiFile2Hash.clear();
311-
// HashContentUtils.mapPsiFile2Content.clear();
312354
info("--- Upload Files took: " + (System.currentTimeMillis() - startTime) + " milliseconds");
355+
}
313356

314-
// ---------------------------------------- Get Analysis
357+
/** Perform costly network request. <b>No cache checks!</b> */
358+
@NotNull
359+
private static List<SuggestionForFile> retrieveSuggestions(@NotNull PsiFile file) {
360+
final Project project = file.getProject();
361+
List<SuggestionForFile> result;
362+
long startTime;
363+
// ---------------------------------------- Create Bundle
315364
startTime = System.currentTimeMillis();
316-
progress.setText(WAITING_FOR_ANALYSIS_TEXT);
365+
info("Creating temporary Bundle from File content");
317366
ProgressManager.checkCanceled();
318-
GetAnalysisResponse getAnalysisResponse = doGetAnalysis(project, bundleId, progress);
319-
result = parseGetAnalysisResponse(project, filesToProceed, getAnalysisResponse, progress);
367+
368+
FileContent fileContent =
369+
new FileContent(
370+
DeepCodeUtils.getDeepCodedFilePath(file), HashContentUtils.getFileContent(file));
371+
FileContentRequest fileContentRequest =
372+
new FileContentRequest(Collections.singletonList(fileContent));
373+
374+
// todo?? it might be cheaper on server side to extend one temporary bundle
375+
// rather then create the new one every time
376+
final CreateBundleResponse createBundleResponse =
377+
DeepCodeRestApi.createBundle(DeepCodeParams.getSessionToken(), fileContentRequest);
378+
isNotSucceed(project, createBundleResponse, "Bad Create/Extend Bundle request: ");
379+
380+
final String bundleId = createBundleResponse.getBundleId();
381+
if (bundleId.isEmpty()) return Collections.emptyList(); // no sense to proceed without bundleId
382+
383+
List<String> missingFiles = createBundleResponse.getMissingFiles();
384+
info(
385+
"--- Create temporary Bundle took: "
386+
+ (System.currentTimeMillis() - startTime)
387+
+ " milliseconds"
388+
+ "\nbundleId: "
389+
+ bundleId
390+
+ "\nmissingFiles: "
391+
+ missingFiles);
392+
if (!missingFiles.isEmpty()) warn("missingFiles is NOT empty!");
393+
394+
// ---------------------------------------- Get Analysis
395+
ProgressManager.checkCanceled();
396+
startTime = System.currentTimeMillis();
397+
GetAnalysisResponse getAnalysisResponse = doGetAnalysis(project, bundleId, null);
398+
result =
399+
parseGetAnalysisResponse(project, Collections.singleton(file), getAnalysisResponse)
400+
.get(file);
401+
mapProject2analysisUrl.put(project, "");
402+
320403
info("--- Get Analysis took: " + (System.currentTimeMillis() - startTime) + " milliseconds");
321404
// progress.stop();
322405
return result;
@@ -328,10 +411,6 @@ private static void uploadFiles(
328411
@NotNull List<String> missingFiles,
329412
@NotNull String bundleId,
330413
@NotNull ProgressIndicator progress) {
331-
if (missingFiles.isEmpty()) {
332-
info("No missingFiles to Upload");
333-
return;
334-
}
335414
Map<String, PsiFile> mapPath2File =
336415
psiFiles.stream().collect(Collectors.toMap(DeepCodeUtils::getDeepCodedFilePath, it -> it));
337416
int fileCounter = 0;
@@ -354,8 +433,8 @@ private static void uploadFiles(
354433
+ "\nFirst broken missingFile: "
355434
+ filePath
356435
+ "\nFull file path example: "
357-
// deepcode ignore checkIsPresent~Optional: collection already is not empty
358-
+ psiFiles.stream().findFirst().get().getVirtualFile().getPath()
436+
// we know collection already is not empty
437+
+ psiFiles.iterator().next().getVirtualFile().getPath()
359438
+ "\nBaseDir path: "
360439
+ project.getBasePath();
361440
}
@@ -471,7 +550,7 @@ private static void doUploadFiles(
471550
private static GetAnalysisResponse doGetAnalysis(
472551
@NotNull Project project,
473552
@NotNull String bundleId,
474-
@NotNull ProgressIndicator progressIndicator) {
553+
@Nullable ProgressIndicator progressIndicator) {
475554
GetAnalysisResponse response;
476555
int counter = 0;
477556
do {
@@ -488,10 +567,12 @@ private static GetAnalysisResponse doGetAnalysis(
488567
if (isNotSucceed(project, response, "Bad GetAnalysis request: "))
489568
return new GetAnalysisResponse();
490569
ProgressManager.checkCanceled();
491-
double progress = response.getProgress();
492-
if (progress <= 0 || progress > 1) progress = ((double) counter) / 200;
493-
progressIndicator.setFraction(progress);
494-
progressIndicator.setText(WAITING_FOR_ANALYSIS_TEXT + (int) (progress * 100) + "% done");
570+
if (progressIndicator != null) {
571+
double progress = response.getProgress();
572+
if (progress <= 0 || progress > 1) progress = ((double) counter) / 200;
573+
progressIndicator.setFraction(progress);
574+
progressIndicator.setText(WAITING_FOR_ANALYSIS_TEXT + (int) (progress * 100) + "% done");
575+
}
495576
// fixme
496577
if (counter == 200) break;
497578
if (response.getStatus().equals("FAILED")) {
@@ -514,8 +595,7 @@ private static GetAnalysisResponse doGetAnalysis(
514595
private static Map<PsiFile, List<SuggestionForFile>> parseGetAnalysisResponse(
515596
@NotNull Project project,
516597
@NotNull Collection<PsiFile> psiFiles,
517-
GetAnalysisResponse response,
518-
@NotNull ProgressIndicator progressIndicator) {
598+
GetAnalysisResponse response) {
519599
Map<PsiFile, List<SuggestionForFile>> result = new HashMap<>();
520600
if (!response.getStatus().equals("DONE")) return EMPTY_MAP;
521601
AnalysisResults analysisResults = response.getAnalysisResults();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public MyBackgroundable(@NotNull Project project, @NotNull Runnable runnable) {
7474
@Override
7575
public void run(@NotNull ProgressIndicator indicator) {
7676
DCLogger.info("New Process started at " + project);
77+
indicator.setIndeterminate(false);
7778
getRunningIndicators(project).add(indicator);
7879

7980
runnable.run();
@@ -136,6 +137,7 @@ public static void runInBackgroundCancellable(
136137
new Task.Backgroundable(project, "DeepCode: Analysing Files...") {
137138
@Override
138139
public void run(@NotNull ProgressIndicator indicator) {
140+
indicator.setIndeterminate(false);
139141

140142
// To let new event cancel the currently running one
141143
ProgressIndicator prevProgressIndicator =
@@ -219,6 +221,7 @@ public static void rescanInBackgroundCancellableDelayed(
219221
new Task.Backgroundable(project, "DeepCode: Analysing Files...") {
220222
@Override
221223
public void run(@NotNull ProgressIndicator indicator) {
224+
indicator.setIndeterminate(false);
222225

223226
// To let new event cancel the currently running one
224227
ProgressIndicator prevProgressIndicator =

0 commit comments

Comments
 (0)