mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 11:35:42 -06:00
Move the polling settings to sys instead of watch utilities
This commit is contained in:
parent
09caaa3775
commit
fa8d4cba78
@ -32,10 +32,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export enum WatchPriority {
|
||||
High,
|
||||
Medium,
|
||||
Low
|
||||
export enum PollingInterval {
|
||||
High = 2000,
|
||||
Medium = 500,
|
||||
Low = 250
|
||||
}
|
||||
|
||||
function getPriorityValues(highPriorityValue: number): [number, number, number] {
|
||||
@ -44,36 +44,47 @@ namespace ts {
|
||||
return [highPriorityValue, mediumPriorityValue, lowPriorityValue];
|
||||
}
|
||||
|
||||
const pollingIntervalsForPriority = getPriorityValues(250);
|
||||
function pollingInterval(watchPriority: WatchPriority): number {
|
||||
function pollingInterval(watchPriority: PollingInterval): number {
|
||||
return pollingIntervalsForPriority[watchPriority];
|
||||
}
|
||||
|
||||
const pollingIntervalsForPriority = getPriorityValues(250);
|
||||
|
||||
/* @internal */
|
||||
export function watchFileUsingPriorityPollingInterval(host: System, fileName: string, callback: FileWatcherCallback, watchPriority: WatchPriority): FileWatcher {
|
||||
export function watchFileUsingPriorityPollingInterval(host: System, fileName: string, callback: FileWatcherCallback, watchPriority: PollingInterval): FileWatcher {
|
||||
return host.watchFile(fileName, callback, pollingInterval(watchPriority));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface DynamicPriorityPollingStatsSet {
|
||||
watchFile(fileName: string, callback: FileWatcherCallback, defaultPriority: WatchPriority): FileWatcher;
|
||||
}
|
||||
export type HostWatchFile = (fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval) => FileWatcher;
|
||||
|
||||
/* @internal */
|
||||
export const missingFileModifiedTime = new Date(0); // Any subsequent modification will occur after this time
|
||||
|
||||
const chunkSizeOrUnchangedThresholdsForPriority = getPriorityValues(32);
|
||||
function chunkSize(watchPriority: WatchPriority) {
|
||||
return chunkSizeOrUnchangedThresholdsForPriority[watchPriority];
|
||||
enum ChunkSize {
|
||||
Low = 32,
|
||||
Medium = 64,
|
||||
High = 256
|
||||
}
|
||||
|
||||
function chunkSize(pollingInterval: PollingInterval) {
|
||||
switch (pollingInterval) {
|
||||
case PollingInterval.Low:
|
||||
return ChunkSize.Low;
|
||||
case PollingInterval.Medium:
|
||||
return ChunkSize.Medium;
|
||||
case PollingInterval.High:
|
||||
return ChunkSize.High;
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function unChangedThreshold(watchPriority: WatchPriority) {
|
||||
return chunkSizeOrUnchangedThresholdsForPriority[watchPriority];
|
||||
export function unChangedThreshold(pollingInterval: PollingInterval) {
|
||||
return chunkSize(pollingInterval);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createDynamicPriorityPollingStatsSet(host: System): DynamicPriorityPollingStatsSet {
|
||||
export function createDynamicPriorityPollingWatchFile(host: System): HostWatchFile {
|
||||
if (!host.getModifiedTime || !host.setTimeout) {
|
||||
throw notImplemented();
|
||||
}
|
||||
@ -83,20 +94,20 @@ namespace ts {
|
||||
unchangedPolls: number;
|
||||
}
|
||||
|
||||
interface WatchPriorityQueue extends Array<WatchedFile> {
|
||||
watchPriority: WatchPriority;
|
||||
interface PollingIntervalQueue extends Array<WatchedFile> {
|
||||
pollingInterval: PollingInterval;
|
||||
pollIndex: number;
|
||||
pollScheduled: boolean;
|
||||
}
|
||||
|
||||
const watchedFiles: WatchedFile[] = [];
|
||||
const changedFilesInLastPoll: WatchedFile[] = [];
|
||||
const priorityQueues = [createPriorityQueue(WatchPriority.High), createPriorityQueue(WatchPriority.Medium), createPriorityQueue(WatchPriority.Low)];
|
||||
return {
|
||||
watchFile
|
||||
};
|
||||
const lowPollingIntervalQueue = createPollingIntervalQueue(PollingInterval.Low);
|
||||
const mediumPollingIntervalQueue = createPollingIntervalQueue(PollingInterval.Medium);
|
||||
const highPollingIntervalQueue = createPollingIntervalQueue(PollingInterval.High);
|
||||
return watchFile;
|
||||
|
||||
function watchFile(fileName: string, callback: FileWatcherCallback, defaultPriority: WatchPriority): FileWatcher {
|
||||
function watchFile(fileName: string, callback: FileWatcherCallback, defaultPollingInterval: PollingInterval): FileWatcher {
|
||||
const file: WatchedFile = {
|
||||
fileName,
|
||||
callback,
|
||||
@ -105,31 +116,30 @@ namespace ts {
|
||||
};
|
||||
watchedFiles.push(file);
|
||||
|
||||
addToPriorityQueue(file, defaultPriority);
|
||||
addToPollingIntervalQueue(file, defaultPollingInterval);
|
||||
return {
|
||||
close: () => {
|
||||
file.isClosed = true;
|
||||
// Remove from watchedFiles
|
||||
unorderedRemoveItem(watchedFiles, file);
|
||||
// Do not update priority queue since that will happen as part of polling
|
||||
// Do not update polling interval queue since that will happen as part of polling
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createPriorityQueue(watchPriority: WatchPriority): WatchPriorityQueue {
|
||||
const queue = [] as WatchPriorityQueue;
|
||||
queue.watchPriority = watchPriority;
|
||||
function createPollingIntervalQueue(pollingInterval: PollingInterval): PollingIntervalQueue {
|
||||
const queue = [] as PollingIntervalQueue;
|
||||
queue.pollingInterval = pollingInterval;
|
||||
queue.pollIndex = 0;
|
||||
queue.pollScheduled = false;
|
||||
return queue;
|
||||
}
|
||||
|
||||
function pollPriorityQueue(queue: WatchPriorityQueue) {
|
||||
const priority = queue.watchPriority;
|
||||
queue.pollIndex = pollQueue(queue, priority, queue.pollIndex, chunkSize(priority));
|
||||
function pollPollingIntervalQueue(queue: PollingIntervalQueue) {
|
||||
queue.pollIndex = pollQueue(queue, queue.pollingInterval, queue.pollIndex, chunkSize(queue.pollingInterval));
|
||||
// Set the next polling index and timeout
|
||||
if (queue.length) {
|
||||
scheduleNextPoll(priority);
|
||||
scheduleNextPoll(queue.pollingInterval);
|
||||
}
|
||||
else {
|
||||
Debug.assert(queue.pollIndex === 0);
|
||||
@ -137,20 +147,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function pollHighPriorityQueue(queue: WatchPriorityQueue) {
|
||||
function pollLowPollingIntervalQueue(queue: PollingIntervalQueue) {
|
||||
// Always poll complete list of changedFilesInLastPoll
|
||||
pollQueue(changedFilesInLastPoll, WatchPriority.High, /*pollIndex*/ 0, changedFilesInLastPoll.length);
|
||||
pollQueue(changedFilesInLastPoll, PollingInterval.Low, /*pollIndex*/ 0, changedFilesInLastPoll.length);
|
||||
|
||||
// Finally do the actual polling of the queue
|
||||
pollPriorityQueue(queue);
|
||||
pollPollingIntervalQueue(queue);
|
||||
// Schedule poll if there are files in changedFilesInLastPoll but no files in the actual queue
|
||||
// as pollPriorityQueue wont schedule for next poll
|
||||
// as pollPollingIntervalQueue wont schedule for next poll
|
||||
if (!queue.pollScheduled && changedFilesInLastPoll.length) {
|
||||
scheduleNextPoll(WatchPriority.High);
|
||||
scheduleNextPoll(PollingInterval.Low);
|
||||
}
|
||||
}
|
||||
|
||||
function pollQueue(queue: WatchedFile[], priority: WatchPriority, pollIndex: number, chunkSize: number) {
|
||||
function pollQueue(queue: WatchedFile[], pollingInterval: PollingInterval, pollIndex: number, chunkSize: number) {
|
||||
// Max visit would be all elements of the queue
|
||||
let needsVisit = queue.length;
|
||||
let definedValueCopyToIndex = pollIndex;
|
||||
@ -175,22 +185,22 @@ namespace ts {
|
||||
// Changed files go to changedFilesInLastPoll queue
|
||||
if (queue !== changedFilesInLastPoll) {
|
||||
queue[pollIndex] = undefined;
|
||||
addChangedFileToHighPriorityQueue(watchedFile);
|
||||
addChangedFileToLowPollingIntervalQueue(watchedFile);
|
||||
}
|
||||
}
|
||||
else if (watchedFile.unchangedPolls !== unChangedThreshold(priority)) {
|
||||
else if (watchedFile.unchangedPolls !== unChangedThreshold(pollingInterval)) {
|
||||
watchedFile.unchangedPolls++;
|
||||
}
|
||||
else if (queue === changedFilesInLastPoll) {
|
||||
// Restart unchangedPollCount for unchanged file and move to high priority queue
|
||||
// Restart unchangedPollCount for unchanged file and move to low polling interval queue
|
||||
watchedFile.unchangedPolls = 1;
|
||||
queue[pollIndex] = undefined;
|
||||
addToPriorityQueue(watchedFile, WatchPriority.High);
|
||||
addToPollingIntervalQueue(watchedFile, PollingInterval.Low);
|
||||
}
|
||||
else if (priority !== WatchPriority.Low) {
|
||||
else if (pollingInterval !== PollingInterval.High) {
|
||||
watchedFile.unchangedPolls++;
|
||||
queue[pollIndex] = undefined;
|
||||
addToPriorityQueue(watchedFile, priority + 1);
|
||||
addToPollingIntervalQueue(watchedFile, pollingInterval === PollingInterval.Low ? PollingInterval.Medium : PollingInterval.High);
|
||||
}
|
||||
|
||||
if (queue[pollIndex]) {
|
||||
@ -219,24 +229,35 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function addToPriorityQueue(file: WatchedFile, priority: WatchPriority) {
|
||||
priorityQueues[priority].push(file);
|
||||
scheduleNextPollIfNotAlreadyScheduled(priority);
|
||||
}
|
||||
|
||||
function addChangedFileToHighPriorityQueue(file: WatchedFile) {
|
||||
changedFilesInLastPoll.push(file);
|
||||
scheduleNextPollIfNotAlreadyScheduled(WatchPriority.High);
|
||||
}
|
||||
|
||||
function scheduleNextPollIfNotAlreadyScheduled(priority: WatchPriority) {
|
||||
if (!priorityQueues[priority].pollScheduled) {
|
||||
scheduleNextPoll(priority);
|
||||
function pollingIntervalQueue(pollingInterval: PollingInterval) {
|
||||
switch (pollingInterval) {
|
||||
case PollingInterval.Low:
|
||||
return lowPollingIntervalQueue;
|
||||
case PollingInterval.Medium:
|
||||
return mediumPollingIntervalQueue;
|
||||
case PollingInterval.High:
|
||||
return highPollingIntervalQueue;
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleNextPoll(priority: WatchPriority) {
|
||||
priorityQueues[priority].pollScheduled = host.setTimeout(priority === WatchPriority.High ? pollHighPriorityQueue : pollPriorityQueue, pollingInterval(priority), priorityQueues[priority]);
|
||||
function addToPollingIntervalQueue(file: WatchedFile, pollingInterval: PollingInterval) {
|
||||
pollingIntervalQueue(pollingInterval).push(file);
|
||||
scheduleNextPollIfNotAlreadyScheduled(pollingInterval);
|
||||
}
|
||||
|
||||
function addChangedFileToLowPollingIntervalQueue(file: WatchedFile) {
|
||||
changedFilesInLastPoll.push(file);
|
||||
scheduleNextPollIfNotAlreadyScheduled(PollingInterval.Low);
|
||||
}
|
||||
|
||||
function scheduleNextPollIfNotAlreadyScheduled(pollingInterval: PollingInterval) {
|
||||
if (!pollingIntervalQueue(pollingInterval).pollScheduled) {
|
||||
scheduleNextPoll(pollingInterval);
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleNextPoll(pollingInterval: PollingInterval) {
|
||||
pollingIntervalQueue(pollingInterval).pollScheduled = host.setTimeout(pollingInterval === PollingInterval.Low ? pollLowPollingIntervalQueue : pollPollingIntervalQueue, pollingInterval, pollingIntervalQueue(pollingInterval));
|
||||
}
|
||||
|
||||
function getModifiedTime(fileName: string) {
|
||||
@ -381,6 +402,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const useNonPollingWatchers = process.env.TSC_NONPOLLING_WATCHER;
|
||||
const tscWatchOption = process.env.TSC_WATCHOPTION;
|
||||
|
||||
const nodeSystem: System = {
|
||||
args: process.argv.slice(2),
|
||||
@ -391,20 +413,6 @@ namespace ts {
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
watchFile: useNonPollingWatchers ? createNonPollingWatchFile() : fsWatchFile,
|
||||
watchDirectory: (directoryName, callback, recursive) => {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
return fsWatchDirectory(directoryName, (eventName, relativeFileName) => {
|
||||
// In watchDirectory we only care about adding and removing files (when event name is
|
||||
// "rename"); changes made within files are handled by corresponding fileWatchers (when
|
||||
// event name is "change")
|
||||
if (eventName === "rename") {
|
||||
// When deleting a file, the passed baseFileName is null
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
|
||||
}
|
||||
}, recursive);
|
||||
},
|
||||
resolvePath: path => _path.resolve(path),
|
||||
fileExists,
|
||||
directoryExists,
|
||||
@ -474,6 +482,20 @@ namespace ts {
|
||||
process.stdout.write("\x1Bc");
|
||||
}
|
||||
};
|
||||
nodeSystem.watchFile = getWatchFile();
|
||||
nodeSystem.watchDirectory = (directoryName, callback, recursive) => {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
return fsWatchDirectory(directoryName, (eventName, relativeFileName) => {
|
||||
// In watchDirectory we only care about adding and removing files (when event name is
|
||||
// "rename"); changes made within files are handled by corresponding fileWatchers (when
|
||||
// event name is "change")
|
||||
if (eventName === "rename") {
|
||||
// When deleting a file, the passed baseFileName is null
|
||||
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
|
||||
}
|
||||
}, recursive);
|
||||
};
|
||||
return nodeSystem;
|
||||
|
||||
function isFileSystemCaseSensitive(): boolean {
|
||||
@ -493,6 +515,20 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getWatchFile(): HostWatchFile {
|
||||
switch (tscWatchOption) {
|
||||
case "PriorityPollingInterval":
|
||||
// Use polling interval based on priority when create watch using host.watchFile
|
||||
return fsWatchFile;
|
||||
case "DynamicPriorityPolling":
|
||||
return createDynamicPriorityPollingWatchFile(nodeSystem);
|
||||
}
|
||||
return useNonPollingWatchers ?
|
||||
createNonPollingWatchFile() :
|
||||
// Default to do not use polling interval as it is before this experiment branch
|
||||
(fileName, callback) => fsWatchFile(fileName, callback);
|
||||
}
|
||||
|
||||
function createNonPollingWatchFile() {
|
||||
// One file can have multiple watchers
|
||||
const fileWatcherCallbacks = createMultiMap<FileWatcherCallback>();
|
||||
|
||||
@ -257,11 +257,11 @@ namespace ts {
|
||||
const writeLog: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? s => { system.write(s); system.write(system.newLine); } : noop;
|
||||
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
|
||||
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
|
||||
const { watchFile, watchFilePath, watchDirectory: watchDirectoryWorker } = getWatchFactory(system, watchLogLevel, writeLog);
|
||||
const { watchFile, watchFilePath, watchDirectory: watchDirectoryWorker } = getWatchFactory(watchLogLevel, writeLog);
|
||||
|
||||
const directoryStructureHost = configFileName ? createCachedDirectoryStructureHost(system) : system;
|
||||
if (configFileName) {
|
||||
watchFile(system, configFileName, scheduleProgramReload, WatchPriority.Low);
|
||||
watchFile(system, configFileName, scheduleProgramReload, PollingInterval.High);
|
||||
}
|
||||
|
||||
const getCurrentDirectory = memoize(() => directoryStructureHost.getCurrentDirectory());
|
||||
@ -414,7 +414,7 @@ namespace ts {
|
||||
hostSourceFile.sourceFile = sourceFile;
|
||||
sourceFile.version = hostSourceFile.version.toString();
|
||||
if (!hostSourceFile.fileWatcher) {
|
||||
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, WatchPriority.High, path);
|
||||
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, PollingInterval.Low, path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -427,7 +427,7 @@ namespace ts {
|
||||
let fileWatcher: FileWatcher;
|
||||
if (sourceFile) {
|
||||
sourceFile.version = "0";
|
||||
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, WatchPriority.High, path);
|
||||
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, PollingInterval.Low, path);
|
||||
sourceFilesCache.set(path, { sourceFile, version: 0, fileWatcher });
|
||||
}
|
||||
else {
|
||||
@ -601,7 +601,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchMissingFilePath(missingFilePath: Path) {
|
||||
return watchFilePath(system, missingFilePath, onMissingFileChange, WatchPriority.Medium, missingFilePath);
|
||||
return watchFilePath(system, missingFilePath, onMissingFileChange, PollingInterval.Medium, missingFilePath);
|
||||
}
|
||||
|
||||
function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) {
|
||||
|
||||
@ -96,9 +96,9 @@ namespace ts {
|
||||
Verbose
|
||||
}
|
||||
|
||||
export type WatchFile<X, Y> = (host: System, file: string, callback: FileWatcherCallback, watchPriority: WatchPriority, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchFile<X, Y> = (host: System, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
|
||||
export type WatchFilePath<X, Y> = (host: System, file: string, callback: FilePathWatcherCallback, watchPriority: WatchPriority, path: Path, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchFilePath<X, Y> = (host: System, file: string, callback: FilePathWatcherCallback, pollingInterval: PollingInterval, path: Path, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchDirectory<X, Y> = (host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
|
||||
export interface WatchFactory<X, Y> {
|
||||
@ -107,30 +107,15 @@ namespace ts {
|
||||
watchDirectory: WatchDirectory<X, Y>;
|
||||
}
|
||||
|
||||
export function getWatchFactory<X = undefined, Y = undefined>(host: System, watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
const value = host.getEnvironmentVariable && host.getEnvironmentVariable("TSC_WATCHFILE");
|
||||
switch (value) {
|
||||
case "PriorityPollingInterval":
|
||||
// Use polling interval based on priority when create watch using host.watchFile
|
||||
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFileUsingPriorityPollingInterval, watchDirectory);
|
||||
case "DynamicPriorityPolling":
|
||||
// Dynamically move frequently changing files to high frequency polling and non changing files to lower frequency
|
||||
return getWatchFactoryWithDynamicPriorityPolling(host, watchLogLevel, log, getDetailWatchInfo);
|
||||
default:
|
||||
return getDefaultWatchFactory(watchLogLevel, log, getDetailWatchInfo);
|
||||
}
|
||||
}
|
||||
|
||||
export function getDefaultWatchFactory<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
// Current behaviour in which polling interval is always 250 ms
|
||||
export function getWatchFactory<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFile, watchDirectory);
|
||||
}
|
||||
|
||||
function getWatchFactoryWith<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined,
|
||||
watchFile: (host: System, file: string, callback: FileWatcherCallback, watchPriority: WatchPriority) => FileWatcher,
|
||||
watchFile: (host: System, file: string, callback: FileWatcherCallback, watchPriority: PollingInterval) => FileWatcher,
|
||||
watchDirectory: (host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags) => FileWatcher): WatchFactory<X, Y> {
|
||||
const createFileWatcher: CreateFileWatcher<WatchPriority, FileWatcherEventKind, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
|
||||
const createFilePathWatcher: CreateFileWatcher<WatchPriority, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
|
||||
const createFileWatcher: CreateFileWatcher<PollingInterval, FileWatcherEventKind, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
|
||||
const createFilePathWatcher: CreateFileWatcher<PollingInterval, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
|
||||
const createDirectoryWatcher: CreateFileWatcher<WatchDirectoryFlags, undefined, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchDirectory);
|
||||
return {
|
||||
watchFile: (host, file, callback, pollingInterval, detailInfo1, detailInfo2) =>
|
||||
@ -141,22 +126,13 @@ namespace ts {
|
||||
createDirectoryWatcher(host, directory, callback, flags, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchDirectory, log, "DirectoryWatcher", getDetailWatchInfo)
|
||||
};
|
||||
|
||||
function watchFilePath(host: System, file: string, callback: FilePathWatcherCallback, watchPriority: WatchPriority, path: Path): FileWatcher {
|
||||
return watchFile(host, file, (fileName, eventKind) => callback(fileName, eventKind, path), watchPriority);
|
||||
function watchFilePath(host: System, file: string, callback: FilePathWatcherCallback, pollingInterval: PollingInterval, path: Path): FileWatcher {
|
||||
return watchFile(host, file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval);
|
||||
}
|
||||
}
|
||||
|
||||
function getWatchFactoryWithDynamicPriorityPolling<X = undefined, Y = undefined>(host: System, watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
const pollingSet = createDynamicPriorityPollingStatsSet(host);
|
||||
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFile, watchDirectory);
|
||||
|
||||
function watchFile(_host: System, file: string, callback: FileWatcherCallback, watchPriority: WatchPriority): FileWatcher {
|
||||
return pollingSet.watchFile(file, callback, watchPriority);
|
||||
}
|
||||
}
|
||||
|
||||
function watchFile(host: System, file: string, callback: FileWatcherCallback, _watchPriority: WatchPriority): FileWatcher {
|
||||
return host.watchFile(file, callback);
|
||||
function watchFile(host: System, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval): FileWatcher {
|
||||
return host.watchFile(file, callback, pollingInterval);
|
||||
}
|
||||
|
||||
function watchDirectory(host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
|
||||
|
||||
@ -2123,15 +2123,15 @@ declare module "fs" {
|
||||
};
|
||||
const files = [file1, libFile];
|
||||
const environmentVariables = createMap<string>();
|
||||
environmentVariables.set("TSC_WATCHFILE", "DynamicPriorityPolling");
|
||||
environmentVariables.set("TSC_WATCHOPTION", "DynamicPriorityPolling");
|
||||
const host = createWatchedSystem(files, { environmentVariables });
|
||||
const watch = createWatchModeWithoutConfigFile([file1.path], host);
|
||||
|
||||
const initialProgram = watch();
|
||||
verifyProgram();
|
||||
|
||||
const mediumPriorityThreshold = unChangedThreshold(WatchPriority.Medium);
|
||||
for (let index = 0; index < mediumPriorityThreshold; index++) {
|
||||
const mediumPollingIntervalThreshold = unChangedThreshold(PollingInterval.Medium);
|
||||
for (let index = 0; index < mediumPollingIntervalThreshold; index++) {
|
||||
// Transition libFile and file1 to low priority queue
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
assert.deepEqual(watch(), initialProgram);
|
||||
@ -2157,14 +2157,14 @@ declare module "fs" {
|
||||
assert.isTrue(host.fileExists(outputFile1));
|
||||
assert.equal(host.readFile(outputFile1), file1.content + host.newLine);
|
||||
|
||||
const newThreshold = unChangedThreshold(WatchPriority.High) + mediumPriorityThreshold;
|
||||
const newThreshold = unChangedThreshold(PollingInterval.Low) + mediumPollingIntervalThreshold;
|
||||
for (; fileUnchangeDetected < newThreshold; fileUnchangeDetected++) {
|
||||
// For low + Medium/high priority
|
||||
// For high + Medium/low polling interval
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
assert.deepEqual(watch(), newProgram);
|
||||
}
|
||||
|
||||
// Everything goes in low priority queue
|
||||
// Everything goes in high polling interval queue
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
assert.deepEqual(watch(), newProgram);
|
||||
|
||||
|
||||
@ -262,6 +262,7 @@ interface Array<T> {}`
|
||||
readonly watchedFiles = createMultiMap<TestFileWatcher>();
|
||||
private readonly executingFilePath: string;
|
||||
private readonly currentDirectory: string;
|
||||
private readonly dynamicPriorityWatchFile: HostWatchFile;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
@ -269,6 +270,9 @@ interface Array<T> {}`
|
||||
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
|
||||
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
|
||||
this.reloadFS(fileOrFolderList);
|
||||
this.dynamicPriorityWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHOPTION") === "DynamicPriorityPolling" ?
|
||||
createDynamicPriorityPollingWatchFile(this) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
getNewLine() {
|
||||
@ -602,7 +606,11 @@ interface Array<T> {}`
|
||||
return Harness.mockHash(s);
|
||||
}
|
||||
|
||||
watchFile(fileName: string, cb: FileWatcherCallback) {
|
||||
watchFile(fileName: string, cb: FileWatcherCallback, pollingInterval: number) {
|
||||
if (this.dynamicPriorityWatchFile) {
|
||||
return this.dynamicPriorityWatchFile(fileName, cb, pollingInterval);
|
||||
}
|
||||
|
||||
const path = this.toFullPath(fileName);
|
||||
const callback: TestFileWatcher = { fileName, cb };
|
||||
this.watchedFiles.add(path, callback);
|
||||
|
||||
@ -449,7 +449,7 @@ namespace ts.server {
|
||||
const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose :
|
||||
this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
|
||||
const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop;
|
||||
this.watchFactory = getDefaultWatchFactory(watchLogLevel, log, getDetailWatchInfo);
|
||||
this.watchFactory = getWatchFactory(watchLogLevel, log, getDetailWatchInfo);
|
||||
}
|
||||
|
||||
toPath(fileName: string) {
|
||||
@ -1116,7 +1116,7 @@ namespace ts.server {
|
||||
this.host,
|
||||
configFileName,
|
||||
(_filename, eventKind) => this.onConfigFileChangeForOpenScriptInfo(configFileName, eventKind),
|
||||
WatchPriority.Low,
|
||||
PollingInterval.High,
|
||||
WatchType.ConfigFileForInferredRoot
|
||||
);
|
||||
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.UpdatedCallback);
|
||||
@ -1500,7 +1500,7 @@ namespace ts.server {
|
||||
this.host,
|
||||
configFileName,
|
||||
(_fileName, eventKind) => this.onConfigChangedForConfiguredProject(project, eventKind),
|
||||
WatchPriority.Low,
|
||||
PollingInterval.High,
|
||||
WatchType.ConfigFilePath,
|
||||
project
|
||||
);
|
||||
@ -1727,7 +1727,7 @@ namespace ts.server {
|
||||
this.host,
|
||||
fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
WatchPriority.Medium,
|
||||
PollingInterval.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
|
||||
@ -932,7 +932,7 @@ namespace ts.server {
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
}
|
||||
},
|
||||
WatchPriority.Medium,
|
||||
PollingInterval.Medium,
|
||||
WatchType.MissingFilePath,
|
||||
this
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user