Skip to content

Commit 3713860

Browse files
committed
Fixes
1 parent 74c6742 commit 3713860

File tree

3 files changed

+28
-91
lines changed

3 files changed

+28
-91
lines changed

src/client/common/utils/cacheUtils.ts

Lines changed: 21 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -78,27 +78,15 @@ export function clearCache() {
7878
resourceSpecificCacheStores.clear();
7979
}
8080

81-
export class InMemoryInterpreterSpecificCache<T> {
82-
private readonly resource: Resource;
83-
private readonly args: any[];
84-
constructor(
85-
private readonly keyPrefix: string,
86-
protected readonly expiryDurationMs: number,
87-
args: [Uri | undefined, ...any[]],
88-
private readonly vscode: VSCodeType = require('vscode')
89-
) {
90-
this.resource = args[0];
91-
this.args = args.slice(1);
81+
export class InMemoryCache<T> {
82+
private readonly _store = new Map<string, CacheData>();
83+
protected get store(): Map<string, CacheData> {
84+
return this._store;
9285
}
86+
constructor(protected readonly expiryDurationMs: number, protected readonly cacheKey: string = '') {}
9387
public get hasData() {
94-
const store = getCacheStore(this.resource, this.vscode);
95-
const key = getCacheKeyFromFunctionArgs(this.keyPrefix, this.args);
96-
const data = store.get(key);
97-
if (!store.has(key) || !data) {
98-
return false;
99-
}
100-
if (this.hasExpired(data.expiry)) {
101-
store.delete(key);
88+
if (!this.store.get(this.cacheKey) || this.hasExpired(this.store.get(this.cacheKey)!.expiry)) {
89+
this.store.delete(this.cacheKey);
10290
return false;
10391
}
10492
return true;
@@ -107,33 +95,24 @@ export class InMemoryInterpreterSpecificCache<T> {
10795
* Returns undefined if there is no data.
10896
* Uses `hasData` to determine whether any cached data exists.
10997
*
98+
* @readonly
11099
* @type {(T | undefined)}
111-
* @memberof InMemoryInterpreterSpecificCache
100+
* @memberof InMemoryCache
112101
*/
113102
public get data(): T | undefined {
114-
if (!this.hasData) {
103+
if (!this.hasData || !this.store.has(this.cacheKey)) {
115104
return;
116105
}
117-
const store = getCacheStore(this.resource, this.vscode);
118-
const key = getCacheKeyFromFunctionArgs(this.keyPrefix, this.args);
119-
const data = store.get(key);
120-
if (!store.has(key) || !data) {
121-
return;
122-
}
123-
return data.value as T;
106+
return this.store.get(this.cacheKey)?.value as T;
124107
}
125108
public set data(value: T | undefined) {
126-
const store = getCacheStore(this.resource, this.vscode);
127-
const key = getCacheKeyFromFunctionArgs(this.keyPrefix, this.args);
128-
store.set(key, {
109+
this.store.set(this.cacheKey, {
129110
expiry: this.calculateExpiry(),
130111
value
131112
});
132113
}
133114
public clear() {
134-
const store = getCacheStore(this.resource, this.vscode);
135-
const key = getCacheKeyFromFunctionArgs(this.keyPrefix, this.args);
136-
store.delete(key);
115+
this.store.clear();
137116
}
138117

139118
/**
@@ -144,7 +123,7 @@ export class InMemoryInterpreterSpecificCache<T> {
144123
* @returns true if the data expired, false otherwise.
145124
*/
146125
protected hasExpired(expiry: number): boolean {
147-
return expiry < Date.now();
126+
return expiry <= Date.now();
148127
}
149128

150129
/**
@@ -158,58 +137,13 @@ export class InMemoryInterpreterSpecificCache<T> {
158137
}
159138
}
160139

161-
export class InMemoryCache<T> {
162-
private readonly _data: { data?: T; hasData: boolean; expiry?: number } = { hasData: false };
163-
constructor(protected readonly expiryDurationMs: number) {}
164-
public get hasData() {
165-
if (!this._data.hasData || !this._data.expiry || this.hasExpired(this._data.expiry)) {
166-
this._data.data = undefined;
167-
this._data.expiry = undefined;
168-
this._data.hasData = false;
169-
return false;
170-
}
171-
return true;
172-
}
173-
/**
174-
* Returns undefined if there is no data.
175-
* Uses `hasData` to determine whether any cached data exists.
176-
*
177-
* @readonly
178-
* @type {(T | undefined)}
179-
* @memberof InMemoryCache
180-
*/
181-
public get data(): T | undefined {
182-
return this.hasData ? this._data.data : undefined;
183-
}
184-
public set data(value: T | undefined) {
185-
this._data.expiry = this.calculateExpiry();
186-
this._data.data = value;
187-
this._data.hasData = true;
188-
}
189-
public clear() {
190-
this._data.data = undefined;
191-
this._data.expiry = undefined;
192-
this._data.hasData = false;
193-
}
194-
195-
/**
196-
* Has this data expired?
197-
* (protected class member to allow for reliable non-data-time-based testing)
198-
*
199-
* @param expiry The date to be tested for expiry.
200-
* @returns true if the data expired, false otherwise.
201-
*/
202-
protected hasExpired(expiry: number): boolean {
203-
return expiry <= Date.now();
140+
export class InMemoryInterpreterSpecificCache<T> extends InMemoryCache<T> {
141+
private readonly resource: Resource;
142+
protected get store() {
143+
return getCacheStore(this.resource, this.vscode);
204144
}
205-
206-
/**
207-
* When should this data item expire?
208-
* (protected class method to allow for reliable non-data-time-based testing)
209-
*
210-
* @returns number representing the expiry time for this item.
211-
*/
212-
protected calculateExpiry(): number {
213-
return Date.now() + this.expiryDurationMs;
145+
constructor(keyPrefix: string, expiryDurationMs: number, args: [Uri | undefined, ...any[]], private readonly vscode: VSCodeType = require('vscode')) {
146+
super(expiryDurationMs, getCacheKeyFromFunctionArgs(keyPrefix, args.slice(1)));
147+
this.resource = args[0];
214148
}
215149
}

src/test/common/utils/cacheUtils.unit.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class TestInMemoryInterpreterSpecificCache extends InMemoryInterpreterSpecificCa
4848
// tslint:disable:no-any max-func-body-length
4949
suite('Common Utils - CacheUtils', () => {
5050
suite('InMemory Cache', () => {
51+
let clock: sinon.SinonFakeTimers;
52+
setup(() => {
53+
clock = sinon.useFakeTimers();
54+
});
55+
teardown(() => clock.restore());
5156
test('Cached item should exist', () => {
5257
const cache = new InMemoryCache(5_000);
5358
cache.data = 'Hello World';
@@ -68,7 +73,6 @@ suite('Common Utils - CacheUtils', () => {
6873
assert.isOk(cache.hasData);
6974
});
7075
test('Cached item should not exist after time expires', () => {
71-
const clock = sinon.useFakeTimers();
7276
const cache = new InMemoryCache(5_000);
7377
cache.data = 'Hello World';
7478

src/test/common/utils/decorators.unit.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ suite('Common Utils - Decorators', function() {
2020
// tslint:disable-next-line: no-invalid-this
2121
this.retries(3);
2222
suite('Cache', () => {
23-
teardown(() => {
24-
clearCache();
25-
});
23+
setup(clearCache);
24+
teardown(clearCache);
2625
function createMockVSC(pythonPath: string): typeof import('vscode') {
2726
return {
2827
workspace: {

0 commit comments

Comments
 (0)