Add logging for TS extension file watcher creation (#185813)

Add logging for extension file watcher creation
This commit is contained in:
Matt Bierner
2023-06-21 15:36:39 -07:00
committed by GitHub
parent 31478cefc5
commit e30b2359c5
4 changed files with 46 additions and 17 deletions

View File

@@ -78,7 +78,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
logDirectoryProvider: noopLogDirectoryProvider,
cancellerFactory: noopRequestCancellerFactory,
versionProvider,
processFactory: new WorkerServerProcessFactory(context.extensionUri),
processFactory: new WorkerServerProcessFactory(context.extensionUri, logger),
activeJsTsEditorTracker,
serviceConfigurationProvider: new BrowserServiceConfigurationProvider(),
experimentTelemetryReporter,

View File

@@ -6,6 +6,7 @@
import * as vscode from 'vscode';
import { Utils } from 'vscode-uri';
import { Schemes } from '../configuration/schemes';
import { Logger } from '../logging/logger';
import { disposeAll, IDisposable } from '../utils/dispose';
import { ResourceMap } from '../utils/resourceMap';
@@ -18,19 +19,27 @@ type DirWatcherEntry = {
export class FileWatcherManager {
private readonly _fileWatchers = new Map<number, {
readonly uri: vscode.Uri;
readonly watcher: vscode.FileSystemWatcher;
readonly dirWatchers: DirWatcherEntry[];
}>();
private readonly _dirWatchers = new ResourceMap<{
readonly uri: vscode.Uri;
readonly watcher: vscode.FileSystemWatcher;
refCount: number;
}>(uri => uri.toString(), { onCaseInsensitiveFileSystem: false });
constructor(
private readonly logger: Logger,
) { }
create(id: number, uri: vscode.Uri, watchParentDirs: boolean, isRecursive: boolean, listeners: { create?: (uri: vscode.Uri) => void; change?: (uri: vscode.Uri) => void; delete?: (uri: vscode.Uri) => void }): void {
this.logger.trace(`Creating file watcher for ${uri.toString()}`);
const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(uri, isRecursive ? '**' : '*'), !listeners.create, !listeners.change, !listeners.delete);
const parentDirWatchers: DirWatcherEntry[] = [];
this._fileWatchers.set(id, { watcher, dirWatchers: parentDirWatchers });
this._fileWatchers.set(id, { uri, watcher, dirWatchers: parentDirWatchers });
if (listeners.create) { watcher.onDidCreate(listeners.create); }
if (listeners.change) { watcher.onDidChange(listeners.change); }
@@ -43,9 +52,10 @@ export class FileWatcherManager {
let parentDirWatcher = this._dirWatchers.get(dirUri);
if (!parentDirWatcher) {
this.logger.trace(`Creating parent dir watcher for ${dirUri.toString()}`);
const glob = new vscode.RelativePattern(Utils.dirname(dirUri), Utils.basename(dirUri));
const parentWatcher = vscode.workspace.createFileSystemWatcher(glob, !listeners.create, true, !listeners.delete);
parentDirWatcher = { refCount: 0, watcher: parentWatcher };
parentDirWatcher = { uri: dirUri, refCount: 0, watcher: parentWatcher };
this._dirWatchers.set(dirUri, parentDirWatcher);
}
parentDirWatcher.refCount++;
@@ -75,15 +85,19 @@ export class FileWatcherManager {
}
}
delete(id: number): void {
const entry = this._fileWatchers.get(id);
if (entry) {
this.logger.trace(`Deleting file watcher for ${entry.uri}`);
for (const dirWatcher of entry.dirWatchers) {
disposeAll(dirWatcher.listeners);
const dirWatcherEntry = this._dirWatchers.get(dirWatcher.uri);
if (dirWatcherEntry) {
if (--dirWatcherEntry.refCount <= 0) {
this.logger.trace(`Deleting parent dir ${dirWatcherEntry.uri}`);
dirWatcherEntry.watcher.dispose();
this._dirWatchers.delete(dirWatcher.uri);
}

View File

@@ -7,6 +7,7 @@ import { ServiceConnection } from '@vscode/sync-api-common/browser';
import { ApiService, Requests } from '@vscode/sync-api-service';
import * as vscode from 'vscode';
import { TypeScriptServiceConfiguration } from '../configuration/configuration';
import { Logger } from '../logging/logger';
import { FileWatcherManager } from './fileWatchingManager';
import type * as Proto from './protocol/protocol';
import { TsServerLog, TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
@@ -30,6 +31,7 @@ type BrowserWatchEvent = {
export class WorkerServerProcessFactory implements TsServerProcessFactory {
constructor(
private readonly _extensionUri: vscode.Uri,
private readonly _logger: Logger,
) { }
public fork(
@@ -47,7 +49,7 @@ export class WorkerServerProcessFactory implements TsServerProcessFactory {
// Explicitly give TS Server its path so it can
// load local resources
'--executingFilePath', tsServerPath,
], tsServerLog);
], tsServerLog, this._logger);
}
}
@@ -60,7 +62,7 @@ class WorkerServerProcess implements TsServerProcess {
private readonly _onDataHandlers = new Set<(data: Proto.Response) => void>();
private readonly _onErrorHandlers = new Set<(err: Error) => void>();
private readonly _onExitHandlers = new Set<(code: number | null, signal: string | null) => void>();
private readonly watches = new FileWatcherManager();
private readonly _watches: FileWatcherManager;
private readonly worker: Worker;
@@ -77,9 +79,12 @@ class WorkerServerProcess implements TsServerProcess {
extensionUri: vscode.Uri,
args: readonly string[],
private readonly tsServerLog: TsServerLog | undefined,
logger: Logger,
) {
this.worker = new Worker(tsServerPath, { name: `TS ${kind} server #${this.id}` });
this._watches = new FileWatcherManager(logger);
const tsserverChannel = new MessageChannel();
const watcherChannel = new MessageChannel();
const syncChannel = new MessageChannel();
@@ -100,12 +105,12 @@ class WorkerServerProcess implements TsServerProcess {
this.watcher.onmessage = (event: MessageEvent<BrowserWatchEvent>) => {
switch (event.data.type) {
case 'dispose': {
this.watches.delete(event.data.id);
this._watches.delete(event.data.id);
break;
}
case 'watchDirectory':
case 'watchFile': {
this.watches.create(event.data.id, vscode.Uri.from(event.data.uri), /*watchParentDirs*/ true, !!event.data.recursive, {
this._watches.create(event.data.id, vscode.Uri.from(event.data.uri), /*watchParentDirs*/ true, !!event.data.recursive, {
change: uri => this.watcher.postMessage({ type: 'watch', event: 'change', uri }),
create: uri => this.watcher.postMessage({ type: 'watch', event: 'create', uri }),
delete: uri => this.watcher.postMessage({ type: 'watch', event: 'delete', uri }),