Path: blob/main/extensions/copilot/test/base/cachingResourceFetcher.ts
13389 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import { ICache, SQLiteCache } from './cache';5import { CacheMode, CacheScope, CurrentTestRunInfo, ICachingResourceFetcher } from './simulationContext';67export const usedResourceCaches = new Set<string>();89class Request<T> {1011constructor(12readonly input: T,13readonly cacheScope: CacheScope,14readonly cacheSalt: string,15readonly inputCacheKey: string16) {17}1819get hash() {20return `${this.cacheScope}:${this.cacheSalt}:${this.inputCacheKey}`;21}2223toJSON() {24return this.input;25}26}2728class ResourceFetcherSQLiteCache<I, R> extends SQLiteCache<Request<I>, R> {29constructor(currentTestRunInfo: CurrentTestRunInfo) {30super('resource', undefined, currentTestRunInfo);31}32}3334export class CachingResourceFetcher implements ICachingResourceFetcher {3536declare readonly _serviceBrand: undefined;3738private cache: ICache<Request<any>, any> | undefined;3940// needs to be static, otherwise concurrent writes will happen, since41// many instances of this will be created42private static Queues = new Map</* cache key */string, Promise<unknown>>();4344constructor(45currentTestRunInfo: CurrentTestRunInfo,46cacheMode: CacheMode47) {48this.cache = cacheMode !== CacheMode.Disable49? new ResourceFetcherSQLiteCache(currentTestRunInfo)50: undefined;51}5253public async invokeWithCache<I, R>(cacheScope: CacheScope, input: I, cacheSalt: string, inputCacheKey: string, fn: (input: I) => Promise<R>): Promise<R> {54if (!this.cache) {55return await fn(input);56}5758// serialize accesses to the same cache key59const promise = Promise.resolve(CachingResourceFetcher.Queues.get(inputCacheKey)).then(async (): Promise<R> => {60const request = new Request(input, cacheScope, cacheSalt, inputCacheKey);61let result: R | undefined = await this.cache!.get(request);6263if (result === undefined) {64result = await fn(input);65await this.cache!.set(request, result);66}6768return result;69});7071CachingResourceFetcher.Queues.set(inputCacheKey, promise.catch(() => { }));7273return promise;74}75}767778