Skip to content

Commit a5d165b

Browse files
authored
Watcher Perf: TypeScript 5.5 asks to watch thousands of non-existing paths (fix microsoft#214765) (microsoft#214842)
1 parent 3ab5eed commit a5d165b

File tree

3 files changed

+21
-7
lines changed

3 files changed

+21
-7
lines changed

src/vs/platform/files/node/watcher/baseWatcher.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ILogMessage, IRecursiveWatcherWithSubscribe, IUniversalWatchRequest, IW
99
import { Emitter, Event } from 'vs/base/common/event';
1010
import { FileChangeType, IFileChange } from 'vs/platform/files/common/files';
1111
import { URI } from 'vs/base/common/uri';
12-
import { DeferredPromise } from 'vs/base/common/async';
12+
import { DeferredPromise, ThrottledDelayer } from 'vs/base/common/async';
1313

1414
export abstract class BaseWatcher extends Disposable implements IWatcher {
1515

@@ -28,6 +28,8 @@ export abstract class BaseWatcher extends Disposable implements IWatcher {
2828
private readonly suspendedWatchRequests = this._register(new DisposableMap<number /* correlation ID */>());
2929
private readonly suspendedWatchRequestsWithPolling = new Set<number /* correlation ID */>();
3030

31+
private readonly updateWatchersDelayer = this._register(new ThrottledDelayer<void>(this.getUpdateWatchersDelay()));
32+
3133
protected readonly suspendedWatchRequestPollingInterval: number = 5007; // node.js default
3234

3335
private joinWatch = new DeferredPromise<void>();
@@ -88,17 +90,21 @@ export abstract class BaseWatcher extends Disposable implements IWatcher {
8890
}
8991
}
9092

91-
return await this.updateWatchers();
93+
return await this.updateWatchers(false /* not delayed */);
9294
} finally {
9395
this.joinWatch.complete();
9496
}
9597
}
9698

97-
private updateWatchers(): Promise<void> {
98-
return this.doWatch([
99+
private updateWatchers(delayed: boolean): Promise<void> {
100+
return this.updateWatchersDelayer.trigger(() => this.doWatch([
99101
...this.allNonCorrelatedWatchRequests,
100102
...Array.from(this.allCorrelatedWatchRequests.values()).filter(request => !this.suspendedWatchRequests.has(request.correlationId))
101-
]);
103+
]), delayed ? this.getUpdateWatchersDelay() : 0);
104+
}
105+
106+
protected getUpdateWatchersDelay(): number {
107+
return 800;
102108
}
103109

104110
isSuspended(request: IUniversalWatchRequest): 'polling' | boolean {
@@ -130,14 +136,14 @@ export abstract class BaseWatcher extends Disposable implements IWatcher {
130136

131137
this.monitorSuspendedWatchRequest(request, disposables);
132138

133-
this.updateWatchers();
139+
this.updateWatchers(true /* delay this call as we might accumulate many failing watch requests on startup */);
134140
}
135141

136142
private resumeWatchRequest(request: IWatchRequestWithCorrelation): void {
137143
this.suspendedWatchRequests.deleteAndDispose(request.correlationId);
138144
this.suspendedWatchRequestsWithPolling.delete(request.correlationId);
139145

140-
this.updateWatchers();
146+
this.updateWatchers(false);
141147
}
142148

143149
private monitorSuspendedWatchRequest(request: IWatchRequestWithCorrelation, disposables: DisposableStore): void {

src/vs/platform/files/test/node/nodejsWatcher.integrationTest.ts

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ import { TestParcelWatcher } from 'vs/platform/files/test/node/parcelWatcher.int
4040

4141
readonly onWatchFail = this._onDidWatchFail.event;
4242

43+
protected override getUpdateWatchersDelay(): number {
44+
return 0;
45+
}
46+
4347
protected override async doWatch(requests: INonRecursiveWatchRequest[]): Promise<void> {
4448
await super.doWatch(requests);
4549
for (const watcher of this.watchers) {

src/vs/platform/files/test/node/parcelWatcher.integrationTest.ts

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class TestParcelWatcher extends ParcelWatcher {
4242
return this.removeDuplicateRequests(requests, false /* validate paths skipped for tests */).map(request => request.path);
4343
}
4444

45+
protected override getUpdateWatchersDelay(): number {
46+
return 0;
47+
}
48+
4549
protected override async doWatch(requests: IRecursiveWatchRequest[]): Promise<void> {
4650
await super.doWatch(requests);
4751
await this.whenReady();

0 commit comments

Comments
 (0)