Skip to content

Commit 47045f2

Browse files
committed
Fix duplicate variant analysis results downloads
This adds a new file `repo_states.json` which tracks the download status of all repositories of a variant analysis. We will write this file when a download has completed and skip a repository download if the repo state is marked as `succeeded`. This should prevent duplicate downloads. This will still queue all repositories, even those which have already been downloaded. However, I expect the actual cost in the download method to be negligible since it's just an in-memory check.
1 parent c36ce48 commit 47045f2

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

extensions/ql-vscode/src/remote-queries/variant-analysis-manager.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import * as fs from 'fs-extra';
2929

3030

3131
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
32+
private static readonly REPO_STATES_FILENAME = 'repo_states.json';
33+
3234
private readonly _onVariantAnalysisAdded = this.push(new EventEmitter<VariantAnalysis>());
3335
public readonly onVariantAnalysisAdded = this._onVariantAnalysisAdded.event;
3436
private readonly _onVariantAnalysisStatusUpdated = this.push(new EventEmitter<VariantAnalysis>());
@@ -43,6 +45,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
4345
private static readonly maxConcurrentDownloads = 3;
4446
private readonly queue = new PQueue({ concurrency: VariantAnalysisManager.maxConcurrentDownloads });
4547

48+
private readonly repoStates = new Map<number, Record<number, VariantAnalysisScannedRepositoryState>>();
49+
4650
constructor(
4751
private readonly ctx: ExtensionContext,
4852
private readonly storagePath: string,
@@ -63,6 +67,15 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
6367
this._onVariantAnalysisRemoved.fire(variantAnalysis);
6468
} else {
6569
await this.setVariantAnalysis(variantAnalysis);
70+
71+
try {
72+
const repoStates = await fs.readJson(this.getRepoStatesStoragePath(variantAnalysis.id));
73+
this.repoStates.set(variantAnalysis.id, repoStates);
74+
} catch (e) {
75+
// Ignore this error, we simply might not have downloaded anything yet
76+
this.repoStates.set(variantAnalysis.id, {});
77+
}
78+
6679
if (status === QueryStatus.InProgress) {
6780
// In this case, last time we checked, the query was still in progress.
6881
// We need to setup the monitor to check for completion.
@@ -148,6 +161,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
148161

149162
await this.prepareStorageDirectory(variantAnalysis.id);
150163

164+
this.repoStates.set(variantAnalysis.id, {});
165+
151166
this._onVariantAnalysisAdded.fire(variantAnalysis);
152167
}
153168

@@ -162,6 +177,14 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
162177

163178
private async onRepoStateUpdated(variantAnalysisId: number, repoState: VariantAnalysisScannedRepositoryState): Promise<void> {
164179
await this.getView(variantAnalysisId)?.updateRepoState(repoState);
180+
181+
let repoStates = this.repoStates.get(variantAnalysisId);
182+
if (!repoStates) {
183+
repoStates = {};
184+
this.repoStates.set(variantAnalysisId, repoStates);
185+
}
186+
187+
repoStates[repoState.repositoryId] = repoState;
165188
}
166189

167190
public async monitorVariantAnalysis(
@@ -176,6 +199,10 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
176199
variantAnalysisSummary: VariantAnalysisApiResponse,
177200
cancellationToken: CancellationToken
178201
): Promise<void> {
202+
if (this.repoStates.get(variantAnalysisSummary.id)?.[scannedRepo.repository.id]?.downloadStatus === VariantAnalysisScannedRepositoryDownloadStatus.Succeeded) {
203+
return;
204+
}
205+
179206
const repoState = {
180207
repositoryId: scannedRepo.repository.id,
181208
downloadStatus: VariantAnalysisScannedRepositoryDownloadStatus.Pending,
@@ -215,6 +242,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
215242

216243
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.Succeeded;
217244
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
245+
246+
await fs.outputJson(this.getRepoStatesStoragePath(variantAnalysisSummary.id), this.repoStates.get(variantAnalysisSummary.id));
218247
}
219248

220249
public async enqueueDownload(
@@ -236,6 +265,13 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
236265
);
237266
}
238267

268+
private getRepoStatesStoragePath(variantAnalysisId: number): string {
269+
return path.join(
270+
this.getVariantAnalysisStorageLocation(variantAnalysisId),
271+
VariantAnalysisManager.REPO_STATES_FILENAME
272+
);
273+
}
274+
239275
/**
240276
* Prepares a directory for storing results for a variant analysis.
241277
* This directory contains a timestamp file, which will be

0 commit comments

Comments
 (0)