@@ -15,13 +15,16 @@ import { CodeQLCliServer } from "../codeql-cli/cli";
1515import { QueryRunner } from "../query-server" ;
1616import { DatabaseItem } from "../databases/local-databases" ;
1717import { Mode } from "./shared/mode" ;
18+ import { CancellationTokenSource } from "vscode" ;
1819
1920// Limit the number of candidates we send to the model in each request
2021// to avoid long requests.
2122// Note that the model may return fewer than this number of candidates.
2223const candidateBatchSize = 20 ;
2324
2425export class AutoModeler {
26+ private readonly jobs : Map < string , CancellationTokenSource > ;
27+
2528 constructor (
2629 private readonly app : App ,
2730 private readonly cliServer : CodeQLCliServer ,
@@ -34,27 +37,56 @@ export class AutoModeler {
3437 private readonly addModeledMethods : (
3538 modeledMethods : Record < string , ModeledMethod > ,
3639 ) => Promise < void > ,
37- ) { }
40+ ) {
41+ this . jobs = new Map < string , CancellationTokenSource > ( ) ;
42+ }
3843
3944 public async startModeling (
4045 dependency : string ,
4146 externalApiUsages : ExternalApiUsage [ ] ,
4247 modeledMethods : Record < string , ModeledMethod > ,
4348 mode : Mode ,
4449 ) : Promise < void > {
45- await this . modelDependency (
46- dependency ,
47- externalApiUsages ,
48- modeledMethods ,
49- mode ,
50- ) ;
50+ if ( this . jobs . has ( dependency ) ) {
51+ return ;
52+ }
53+
54+ const cancellationTokenSource = new CancellationTokenSource ( ) ;
55+ this . jobs . set ( dependency , cancellationTokenSource ) ;
56+
57+ try {
58+ await this . modelDependency (
59+ dependency ,
60+ externalApiUsages ,
61+ modeledMethods ,
62+ mode ,
63+ cancellationTokenSource ,
64+ ) ;
65+ } finally {
66+ this . jobs . delete ( dependency ) ;
67+ }
68+ }
69+
70+ public async stopModeling ( dependency : string ) : Promise < void > {
71+ void extLogger . log ( `Stopping modeling for dependency ${ dependency } ` ) ;
72+ const cancellationTokenSource = this . jobs . get ( dependency ) ;
73+ if ( cancellationTokenSource ) {
74+ cancellationTokenSource . cancel ( ) ;
75+ }
76+ }
77+
78+ public async stopAllModeling ( ) : Promise < void > {
79+ for ( const cancellationTokenSource of this . jobs . values ( ) ) {
80+ cancellationTokenSource . cancel ( ) ;
81+ }
5182 }
5283
5384 private async modelDependency (
5485 dependency : string ,
5586 externalApiUsages : ExternalApiUsage [ ] ,
5687 modeledMethods : Record < string , ModeledMethod > ,
5788 mode : Mode ,
89+ cancellationTokenSource : CancellationTokenSource ,
5890 ) : Promise < void > {
5991 void extLogger . log ( `Modeling dependency ${ dependency } ` ) ;
6092 await withProgress ( async ( progress ) => {
@@ -79,6 +111,10 @@ export class AutoModeler {
79111 ) ;
80112 try {
81113 for ( let i = 0 ; i < batchNumber ; i ++ ) {
114+ if ( cancellationTokenSource . token . isCancellationRequested ) {
115+ break ;
116+ }
117+
82118 const start = i * candidateBatchSize ;
83119 const end = start + candidateBatchSize ;
84120 const candidatesToProcess = allCandidateMethods . slice ( start , end ) ;
@@ -100,6 +136,7 @@ export class AutoModeler {
100136 mode ,
101137 progress ,
102138 maxStep ,
139+ cancellationTokenSource ,
103140 ) ;
104141 }
105142 } finally {
@@ -114,6 +151,7 @@ export class AutoModeler {
114151 mode : Mode ,
115152 progress : ProgressCallback ,
116153 maxStep : number ,
154+ cancellationTokenSource : CancellationTokenSource ,
117155 ) : Promise < void > {
118156 const usages = await runAutoModelQueries ( {
119157 mode,
@@ -123,6 +161,7 @@ export class AutoModeler {
123161 queryStorageDir : this . queryStorageDir ,
124162 databaseItem : this . databaseItem ,
125163 progress : ( update ) => progress ( { ...update , maxStep } ) ,
164+ cancellationTokenSource,
126165 } ) ;
127166 if ( ! usages ) {
128167 return ;
0 commit comments