mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-28 11:18:18 +01:00
b230b603ce
The `getLanguageModelCache` eviction check used `===` to compare the current entry count against `maxEntries`, which triggered eviction as soon as the cache reached its maximum size. At steady state the cache therefore held only `maxEntries - 1` entries instead of the intended `maxEntries`. Changing the condition to `>` ensures eviction only occurs when the count exceeds `maxEntries`, allowing the cache to retain the full number of intended entries. The same fix was applied to the HTML and CSS language servers which contain an identical copy of this file.
83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { TextDocument } from 'vscode-languageserver';
|
|
|
|
export interface LanguageModelCache<T> {
|
|
get(document: TextDocument): T;
|
|
onDocumentRemoved(document: TextDocument): void;
|
|
dispose(): void;
|
|
}
|
|
|
|
export function getLanguageModelCache<T>(maxEntries: number, cleanupIntervalTimeInSec: number, parse: (document: TextDocument) => T): LanguageModelCache<T> {
|
|
let languageModels: { [uri: string]: { version: number; languageId: string; cTime: number; languageModel: T } } = {};
|
|
let nModels = 0;
|
|
|
|
let cleanupInterval: NodeJS.Timeout | undefined = undefined;
|
|
if (cleanupIntervalTimeInSec > 0) {
|
|
cleanupInterval = setInterval(() => {
|
|
const cutoffTime = Date.now() - cleanupIntervalTimeInSec * 1000;
|
|
const uris = Object.keys(languageModels);
|
|
for (const uri of uris) {
|
|
const languageModelInfo = languageModels[uri];
|
|
if (languageModelInfo.cTime < cutoffTime) {
|
|
delete languageModels[uri];
|
|
nModels--;
|
|
}
|
|
}
|
|
}, cleanupIntervalTimeInSec * 1000);
|
|
}
|
|
|
|
return {
|
|
get(document: TextDocument): T {
|
|
const version = document.version;
|
|
const languageId = document.languageId;
|
|
const languageModelInfo = languageModels[document.uri];
|
|
if (languageModelInfo && languageModelInfo.version === version && languageModelInfo.languageId === languageId) {
|
|
languageModelInfo.cTime = Date.now();
|
|
return languageModelInfo.languageModel;
|
|
}
|
|
const languageModel = parse(document);
|
|
languageModels[document.uri] = { languageModel, version, languageId, cTime: Date.now() };
|
|
if (!languageModelInfo) {
|
|
nModels++;
|
|
}
|
|
|
|
if (nModels > maxEntries) {
|
|
let oldestTime = Number.MAX_VALUE;
|
|
let oldestUri = null;
|
|
for (const uri in languageModels) {
|
|
const languageModelInfo = languageModels[uri];
|
|
if (languageModelInfo.cTime < oldestTime) {
|
|
oldestUri = uri;
|
|
oldestTime = languageModelInfo.cTime;
|
|
}
|
|
}
|
|
if (oldestUri) {
|
|
delete languageModels[oldestUri];
|
|
nModels--;
|
|
}
|
|
}
|
|
return languageModel;
|
|
|
|
},
|
|
onDocumentRemoved(document: TextDocument) {
|
|
const uri = document.uri;
|
|
if (languageModels[uri]) {
|
|
delete languageModels[uri];
|
|
nModels--;
|
|
}
|
|
},
|
|
dispose() {
|
|
if (typeof cleanupInterval !== 'undefined') {
|
|
clearInterval(cleanupInterval);
|
|
cleanupInterval = undefined;
|
|
languageModels = {};
|
|
nModels = 0;
|
|
}
|
|
}
|
|
};
|
|
}
|