Skip to content

Commit e7a5def

Browse files
Merge pull request #2462 from github/robertbrignull/cached-operation
Move CachedOperation to a new file
2 parents 00bd7b7 + 56d6f19 commit e7a5def

File tree

3 files changed

+71
-72
lines changed

3 files changed

+71
-72
lines changed

extensions/ql-vscode/src/helpers.ts

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -584,77 +584,6 @@ export async function getPrimaryDbscheme(
584584
return dbscheme;
585585
}
586586

587-
/**
588-
* A cached mapping from strings to value of type U.
589-
*/
590-
export class CachedOperation<U> {
591-
private readonly operation: (t: string, ...args: any[]) => Promise<U>;
592-
private readonly cached: Map<string, U>;
593-
private readonly lru: string[];
594-
private readonly inProgressCallbacks: Map<
595-
string,
596-
Array<[(u: U) => void, (reason?: any) => void]>
597-
>;
598-
599-
constructor(
600-
operation: (t: string, ...args: any[]) => Promise<U>,
601-
private cacheSize = 100,
602-
) {
603-
this.operation = operation;
604-
this.lru = [];
605-
this.inProgressCallbacks = new Map<
606-
string,
607-
Array<[(u: U) => void, (reason?: any) => void]>
608-
>();
609-
this.cached = new Map<string, U>();
610-
}
611-
612-
async get(t: string, ...args: any[]): Promise<U> {
613-
// Try and retrieve from the cache
614-
const fromCache = this.cached.get(t);
615-
if (fromCache !== undefined) {
616-
// Move to end of lru list
617-
this.lru.push(
618-
this.lru.splice(
619-
this.lru.findIndex((v) => v === t),
620-
1,
621-
)[0],
622-
);
623-
return fromCache;
624-
}
625-
// Otherwise check if in progress
626-
const inProgressCallback = this.inProgressCallbacks.get(t);
627-
if (inProgressCallback !== undefined) {
628-
// If so wait for it to resolve
629-
return await new Promise((resolve, reject) => {
630-
inProgressCallback.push([resolve, reject]);
631-
});
632-
}
633-
634-
// Otherwise compute the new value, but leave a callback to allow sharing work
635-
const callbacks: Array<[(u: U) => void, (reason?: any) => void]> = [];
636-
this.inProgressCallbacks.set(t, callbacks);
637-
try {
638-
const result = await this.operation(t, ...args);
639-
callbacks.forEach((f) => f[0](result));
640-
this.inProgressCallbacks.delete(t);
641-
if (this.lru.length > this.cacheSize) {
642-
const toRemove = this.lru.shift()!;
643-
this.cached.delete(toRemove);
644-
}
645-
this.lru.push(t);
646-
this.cached.set(t, result);
647-
return result;
648-
} catch (e) {
649-
// Rethrow error on all callbacks
650-
callbacks.forEach((f) => f[1](e));
651-
throw e;
652-
} finally {
653-
this.inProgressCallbacks.delete(t);
654-
}
655-
}
656-
}
657-
658587
/**
659588
* The following functions al heuristically determine metadata about databases.
660589
*/

extensions/ql-vscode/src/language-support/contextual/template-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from "../../common/vscode/archive-filesystem-provider";
1818
import { CodeQLCliServer } from "../../codeql-cli/cli";
1919
import { DatabaseManager } from "../../databases/local-databases";
20-
import { CachedOperation } from "../../helpers";
20+
import { CachedOperation } from "../../pure/cached-operation";
2121
import { ProgressCallback, withProgress } from "../../common/vscode/progress";
2222
import { KeyType } from "./key-type";
2323
import {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* A cached mapping from strings to value of type U.
3+
*/
4+
export class CachedOperation<U> {
5+
private readonly operation: (t: string, ...args: any[]) => Promise<U>;
6+
private readonly cached: Map<string, U>;
7+
private readonly lru: string[];
8+
private readonly inProgressCallbacks: Map<
9+
string,
10+
Array<[(u: U) => void, (reason?: any) => void]>
11+
>;
12+
13+
constructor(
14+
operation: (t: string, ...args: any[]) => Promise<U>,
15+
private cacheSize = 100,
16+
) {
17+
this.operation = operation;
18+
this.lru = [];
19+
this.inProgressCallbacks = new Map<
20+
string,
21+
Array<[(u: U) => void, (reason?: any) => void]>
22+
>();
23+
this.cached = new Map<string, U>();
24+
}
25+
26+
async get(t: string, ...args: any[]): Promise<U> {
27+
// Try and retrieve from the cache
28+
const fromCache = this.cached.get(t);
29+
if (fromCache !== undefined) {
30+
// Move to end of lru list
31+
this.lru.push(
32+
this.lru.splice(
33+
this.lru.findIndex((v) => v === t),
34+
1,
35+
)[0],
36+
);
37+
return fromCache;
38+
}
39+
// Otherwise check if in progress
40+
const inProgressCallback = this.inProgressCallbacks.get(t);
41+
if (inProgressCallback !== undefined) {
42+
// If so wait for it to resolve
43+
return await new Promise((resolve, reject) => {
44+
inProgressCallback.push([resolve, reject]);
45+
});
46+
}
47+
48+
// Otherwise compute the new value, but leave a callback to allow sharing work
49+
const callbacks: Array<[(u: U) => void, (reason?: any) => void]> = [];
50+
this.inProgressCallbacks.set(t, callbacks);
51+
try {
52+
const result = await this.operation(t, ...args);
53+
callbacks.forEach((f) => f[0](result));
54+
this.inProgressCallbacks.delete(t);
55+
if (this.lru.length > this.cacheSize) {
56+
const toRemove = this.lru.shift()!;
57+
this.cached.delete(toRemove);
58+
}
59+
this.lru.push(t);
60+
this.cached.set(t, result);
61+
return result;
62+
} catch (e) {
63+
// Rethrow error on all callbacks
64+
callbacks.forEach((f) => f[1](e));
65+
throw e;
66+
} finally {
67+
this.inProgressCallbacks.delete(t);
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)