Skip to content

Commit

Permalink
Use document level cache to improve parsing performance #463
Browse files Browse the repository at this point in the history
  • Loading branch information
Huachao committed Dec 30, 2019
1 parent 5c3c0c7 commit ba3145a
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 55 deletions.
1 change: 0 additions & 1 deletion src/controllers/environmentController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export class EnvironmentController {
const document = getCurrentTextDocument();
if (document && languages.match(['http', 'plaintext'], document)) {
this._environmentStatusBarItem.show();
return;
} else {
this._environmentStatusBarItem.hide();
}
Expand Down
2 changes: 1 addition & 1 deletion src/models/configurationSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class RestClientSettings implements IRestClientSettings {

private initializeSettings() {
const document = getCurrentTextDocument();
const restClientSettings = workspace.getConfiguration("rest-client", document ? document.uri : null);
const restClientSettings = workspace.getConfiguration("rest-client", document?.uri);
this.followRedirect = restClientSettings.get<boolean>("followredirect", true);
this.defaultHeaders = restClientSettings.get<RequestHeaders>("defaultHeaders",
{
Expand Down
34 changes: 34 additions & 0 deletions src/models/documentCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { TextDocument } from 'vscode';

export class DocumentCache<T> {
private _cache: Map<string, T>;

public constructor() {
this._cache = new Map<string, T>();
}

public get(document: TextDocument): T | undefined {
return this._cache.get(this.getKey(document));
}

public set(document: TextDocument, value: T): this {
this._cache.set(this.getKey(document), value);
return this;
}

public delete(document: TextDocument): boolean {
return this._cache.delete(this.getKey(document));
}

public clear(): void {
this._cache.clear();
}

public has(document: TextDocument): boolean {
return this._cache.has(this.getKey(document));
}

private getKey(document: TextDocument): string {
return `${document.uri.toString()}@${document.version}`;
}
}
9 changes: 9 additions & 0 deletions src/providers/customVariableDiagnosticsProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ConfigurationChangeEvent, Diagnostic, DiagnosticCollection, DiagnosticSeverity, Disposable, languages, Position, Range, TextDocument, workspace } from 'vscode';
import * as Constants from '../common/constants';
import { DocumentCache } from '../models/documentCache';
import { ResolveState } from '../models/httpVariableResolveResult';
import { RequestVariableCacheKey } from '../models/requestVariableCacheKey';
import { VariableType } from '../models/variableType';
Expand All @@ -24,6 +25,8 @@ export class CustomVariableDiagnosticsProvider {

private timer: NodeJS.Timer | undefined;

private fileVaraibleReferenceCache = new DocumentCache<Map<string, VariableWithPosition[]>>();

constructor() {
this.disposables.push(
workspace.onDidOpenTextDocument(document => this.queue(document)),
Expand Down Expand Up @@ -128,6 +131,10 @@ export class CustomVariableDiagnosticsProvider {
}

private findVariableReferences(document: TextDocument): Map<string, VariableWithPosition[]> {
if (this.fileVaraibleReferenceCache.has(document)) {
return this.fileVaraibleReferenceCache.get(document)!;
}

const vars = new Map<string, VariableWithPosition[]>();
const lines = document.getText().split(Constants.LineSplitterRegex);
const pattern = /\{\{(\w+)(\..*?)*\}\}/g;
Expand All @@ -149,6 +156,8 @@ export class CustomVariableDiagnosticsProvider {
}
});

this.fileVaraibleReferenceCache.set(document, vars);

return vars;
}
}
9 changes: 9 additions & 0 deletions src/providers/fileVariableReferencesCodeLensProvider.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { CancellationToken, CodeLens, CodeLensProvider, Command, Location, Range, TextDocument } from 'vscode';
import * as Constants from '../common/constants';
import { DocumentCache } from '../models/documentCache';
import { Selector } from '../utils/selector';
import { VariableUtility } from '../utils/variableUtility';

export class FileVariableReferencesCodeLensProvider implements CodeLensProvider {
private readonly fileVariableReferenceCache = new DocumentCache<CodeLens[]>();

public provideCodeLenses(document: TextDocument, token: CancellationToken): Promise<CodeLens[]> {
if (this.fileVariableReferenceCache.has(document)) {
return Promise.resolve(this.fileVariableReferenceCache.get(document)!);
}

const blocks: CodeLens[] = [];
const lines: string[] = document.getText().split(Constants.LineSplitterRegex);
const requestRanges: [number, number][] = Selector.getRequestRanges(lines, { ignoreFileVariableDefinitionLine: false });
Expand Down Expand Up @@ -32,6 +39,8 @@ export class FileVariableReferencesCodeLensProvider implements CodeLensProvider
}
}

this.fileVariableReferenceCache.set(document, blocks);

return Promise.resolve(blocks);
}

Expand Down
60 changes: 29 additions & 31 deletions src/utils/httpVariableProviders/fileVariableProvider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { TextDocument } from 'vscode';
import * as Constants from '../../common/constants';
import { DocumentCache } from '../../models/documentCache';
import { ResolveErrorMessage } from '../../models/httpVariableResolveResult';
import { VariableType } from '../../models/variableType';
import { md5 } from '../misc';
import { EnvironmentVariableProvider } from './environmentVariableProvider';
import { HttpVariable, HttpVariableProvider } from './httpVariableProvider';
import { RequestVariableProvider } from './requestVariableProvider';
Expand Down Expand Up @@ -33,9 +33,7 @@ export class FileVariableProvider implements HttpVariableProvider {
EnvironmentVariableProvider.Instance,
];

private readonly cache = new Map<string, FileVariableValue[]>();

private readonly fileMD5Hash = new Map<string, string>();
private readonly fileVariableCache = new DocumentCache<FileVariableValue[]>();

private constructor() {
}
Expand Down Expand Up @@ -65,51 +63,51 @@ export class FileVariableProvider implements HttpVariableProvider {
}

private async getFileVariables(document: TextDocument): Promise<FileVariableValue[]> {
const file = document.uri.toString();
if (this.fileVariableCache.has(document)) {
return this.fileVariableCache.get(document)!;
}

const fileContent = document.getText();
const fileHash = md5(fileContent);
if (!this.cache.has(file) || fileHash !== this.fileMD5Hash.get(file)) {
const variables = new Map<string, FileVariableValue>();
for (const line of fileContent.split(Constants.LineSplitterRegex)) {
const regex = new RegExp(Constants.FileVariableDefinitionRegex, 'g');
let match: RegExpExecArray | null;
while (match = regex.exec(line)) {
const [, key, originalValue] = match;
let value = "";
let isPrevCharEscape = false;
for (const currentChar of originalValue) {
if (isPrevCharEscape) {
isPrevCharEscape = false;
value += this.escapee.get(currentChar) || currentChar;
} else {
if (currentChar === "\\") {
isPrevCharEscape = true;
continue;
}
value += currentChar;
const variables = new Map<string, FileVariableValue>();
for (const line of fileContent.split(Constants.LineSplitterRegex)) {
const regex = new RegExp(Constants.FileVariableDefinitionRegex, 'g');
let match: RegExpExecArray | null;
while (match = regex.exec(line)) {
const [, key, originalValue] = match;
let value = "";
let isPrevCharEscape = false;
for (const currentChar of originalValue) {
if (isPrevCharEscape) {
isPrevCharEscape = false;
value += this.escapee.get(currentChar) || currentChar;
} else {
if (currentChar === "\\") {
isPrevCharEscape = true;
continue;
}
value += currentChar;
}
variables.set(key, { name: key, value });
}
variables.set(key, { name: key, value });
}
this.cache.set(file, [...variables.values()]);
this.fileMD5Hash.set(file, fileHash);
}

return this.cache.get(file)!;
const values = [...variables.values()];
this.fileVariableCache.set(document, values);
return values;
}

private async resolveFileVariables(document: TextDocument, variables: FileVariableValue[]): Promise<Map<string, string>> {
// Resolve non-file variables in variable value
const fileVariableNames = new Set(variables.map(v => v.name));
const resolvedVariables = await Promise.all(variables.map(
async ({name, value}) => {
async ({ name, value }) => {
const parsedValue = await this.processNonFileVariableValue(document, value, fileVariableNames);
return { name, value: parsedValue };
}
));

const variableMap = new Map(resolvedVariables.map(({name, value}): [string, string] => [name, value]));
const variableMap = new Map(resolvedVariables.map(({ name, value }): [string, string] => [name, value]));
const dependentVariables = new Map<string, string[]>();
const dependencyCount = new Map<string, number>();
const noDependencyVariables: string[] = [];
Expand Down
34 changes: 16 additions & 18 deletions src/utils/httpVariableProviders/requestVariableProvider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { TextDocument } from 'vscode';
import * as Constants from '../../common/constants';
import { DocumentCache } from '../../models/documentCache';
import { ResolveErrorMessage, ResolveResult, ResolveState, ResolveWarningMessage } from '../../models/httpVariableResolveResult';
import { RequestVariableCacheKey } from '../../models/requestVariableCacheKey';
import { VariableType } from '../../models/variableType';
import { md5 } from '../misc';
import { RequestVariableCache } from '../requestVariableCache';
import { RequestVariableCacheValueProcessor } from '../requestVariableCacheValueProcessor';
import { HttpVariable, HttpVariableProvider } from './httpVariableProvider';
Expand All @@ -19,9 +19,7 @@ export class RequestVariableProvider implements HttpVariableProvider {
return RequestVariableProvider._instance;
}

private readonly cache = new Map<string, string[]>();

private readonly fileMD5Hash = new Map<string, string>();
private readonly requestVariableCache = new DocumentCache<string[]>();

private constructor() {
}
Expand All @@ -42,7 +40,7 @@ export class RequestVariableProvider implements HttpVariableProvider {
}
const value = RequestVariableCache.get(new RequestVariableCacheKey(variableName, document));
if (value === undefined) {
return { name: variableName , warning: ResolveWarningMessage.RequestVariableNotSent };
return { name: variableName, warning: ResolveWarningMessage.RequestVariableNotSent };
}

const resolveResult = RequestVariableCacheValueProcessor.resolveRequestVariable(value, name);
Expand All @@ -55,23 +53,23 @@ export class RequestVariableProvider implements HttpVariableProvider {
}

private getRequestVariables(document: TextDocument): string[] {
const file = document.uri.toString();
if (this.requestVariableCache.has(document)) {
return this.requestVariableCache.get(document)!;
}

const fileContent = document.getText();
const fileHash = md5(fileContent);
if (!this.cache.has(file) || fileHash !== this.fileMD5Hash.get(file)) {
const requestVariableReferenceRegex = new RegExp(Constants.RequestVariableDefinitionWithNameRegexFactory('\\w+'), 'mg');
const requestVariableReferenceRegex = new RegExp(Constants.RequestVariableDefinitionWithNameRegexFactory('\\w+'), 'mg');

const variableNames = new Set<string>();
let match: RegExpExecArray | null;
while (match = requestVariableReferenceRegex.exec(fileContent)) {
const name = match[1];
variableNames.add(name);
}
this.cache.set(file, [...variableNames]);
this.fileMD5Hash.set(file, fileHash);
const variableNames = new Set<string>();
let match: RegExpExecArray | null;
while (match = requestVariableReferenceRegex.exec(fileContent)) {
const name = match[1];
variableNames.add(name);
}

return this.cache.get(file)!;
const values = [...variableNames];
this.requestVariableCache.set(document, values);
return values;
}

private convertToHttpVariable(name: string, result: ResolveResult): HttpVariable {
Expand Down
4 changes: 0 additions & 4 deletions src/utils/requestVariableCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ export class RequestVariableCache {
return RequestVariableCache.eventEmitter.event;
}

public static get size(): number {
return RequestVariableCache.cache.size;
}

public static add(cacheKey: RequestVariableCacheKey, value: RequestVariableCacheValue) {
RequestVariableCache.cache.set(cacheKey.getCacheKey(), value);
const { key: name, document } = cacheKey;
Expand Down

0 comments on commit ba3145a

Please sign in to comment.