提交 19472a95 编写于 作者: J Johannes Rieken 提交者: GitHub

Merge pull request #16366 from Microsoft/joh/cached_data

Make use of v8 cached data
......@@ -413,8 +413,12 @@ function getShellEnvironment(): TPromise<platform.IProcessEnvironment> {
}
function createPaths(environmentService: IEnvironmentService): TPromise<any> {
const paths = [environmentService.appSettingsHome, environmentService.userProductHome, environmentService.extensionsPath];
const paths = [
environmentService.appSettingsHome,
environmentService.userProductHome,
environmentService.extensionsPath,
environmentService.nodeCachedDataDir
];
return TPromise.join(paths.map(p => mkdirp(p))) as TPromise<any>;
}
......
......@@ -88,6 +88,8 @@ export interface IWindowConfiguration extends ParsedArgs {
filesToOpen?: IPath[];
filesToCreate?: IPath[];
filesToDiff?: IPath[];
nodeCachedDataDir: string;
}
export enum ReadyState {
......
......@@ -624,6 +624,7 @@ export class WindowsManager implements IWindowsMainService {
configuration.filesToOpen = filesToOpen;
configuration.filesToCreate = filesToCreate;
configuration.filesToDiff = filesToDiff;
configuration.nodeCachedDataDir = this.environmentService.isBuilt && this.environmentService.nodeCachedDataDir;
return configuration;
}
......@@ -1227,4 +1228,4 @@ export class WindowsManager implements IWindowsMainService {
}, 10 /* delay to unwind callback stack (IPC) */);
}
}
}
\ No newline at end of file
}
......@@ -191,6 +191,20 @@ var AMDLoader;
if (!Array.isArray(options.nodeModules)) {
options.nodeModules = [];
}
if (typeof options.nodeCachedDataWriteDelay !== 'number' || options.nodeCachedDataWriteDelay < 0) {
options.nodeCachedDataWriteDelay = 1000 * 7;
}
if (typeof options.onNodeCachedDataError !== 'function') {
options.onNodeCachedDataError = function (err) {
if (err.errorCode === 'cachedDataRejected') {
console.warn('Rejected cached data from file: ' + err.path);
}
else if (err.errorCode === 'unlink' || err.errorCode === 'writeFile') {
console.error('Problems writing cached data file: ' + err.path);
console.error(err.detail);
}
};
}
return options;
};
ConfigurationOptionsUtil.mergeConfigurationOptions = function (overwrite, base) {
......@@ -906,7 +920,6 @@ var AMDLoader;
this._queuedDefineCalls = [];
this._loadingScriptsCount = 0;
this._resolvedScriptPaths = {};
this._checksums = {};
}
ModuleManager._findRelevantLocationInStack = function (needle, stack) {
var normalize = function (str) { return str.replace(/\\/g, '/'); };
......@@ -968,12 +981,6 @@ var AMDLoader;
ModuleManager.prototype.getLoaderEvents = function () {
return this.getRecorder().getEvents();
};
ModuleManager.prototype.recordChecksum = function (scriptSrc, checksum) {
this._checksums[scriptSrc] = checksum;
};
ModuleManager.prototype.getChecksums = function () {
return this._checksums;
};
/**
* Defines a module.
* @param id @see defineModule
......@@ -1297,9 +1304,6 @@ var AMDLoader;
result.getStats = function () {
return _this.getLoaderEvents();
};
result.getChecksums = function () {
return _this.getChecksums();
};
result.__$__nodeRequire = global.nodeRequire;
return result;
};
......@@ -1718,7 +1722,6 @@ var AMDLoader;
NodeScriptLoader.prototype.load = function (scriptSrc, callback, errorback, recorder) {
var _this = this;
var opts = this._moduleManager.getConfigurationOptions();
var checksum = opts.checksum || false;
var nodeRequire = (opts.nodeRequire || global.nodeRequire);
var nodeInstrumenter = (opts.nodeInstrumenter || function (c) { return c; });
this._init(nodeRequire);
......@@ -1745,15 +1748,6 @@ var AMDLoader;
errorback(err);
return;
}
if (checksum) {
var hash = _this._crypto
.createHash('md5')
.update(data, 'utf8')
.digest('base64')
.replace(/=+$/, '');
_this._moduleManager.recordChecksum(scriptSrc, hash);
}
recorder.record(LoaderEventType.NodeBeginEvaluatingScript, scriptSrc);
var vmScriptSrc = _this._path.normalize(scriptSrc);
// Make the script src friendly towards electron
if (isElectronRenderer) {
......@@ -1771,19 +1765,74 @@ var AMDLoader;
contents = prefix + data + suffix;
}
contents = nodeInstrumenter(contents, vmScriptSrc);
var r;
if (/^v0\.12/.test(process.version)) {
r = _this._vm.runInThisContext(contents, { filename: vmScriptSrc });
if (!opts.nodeCachedDataDir) {
_this._loadAndEvalScript(scriptSrc, vmScriptSrc, contents, { filename: vmScriptSrc }, recorder);
callback();
}
else {
r = _this._vm.runInThisContext(contents, vmScriptSrc);
var cachedDataPath_1 = _this._getCachedDataPath(opts.nodeCachedDataDir, scriptSrc);
_this._fs.readFile(cachedDataPath_1, function (err, data) {
// create script options
var scriptOptions = {
filename: vmScriptSrc,
produceCachedData: typeof data === 'undefined',
cachedData: data
};
var script = _this._loadAndEvalScript(scriptSrc, vmScriptSrc, contents, scriptOptions, recorder);
callback();
// cached code after math
if (script.cachedDataRejected) {
// data rejected => delete cache file
opts.onNodeCachedDataError({
errorCode: 'cachedDataRejected',
path: cachedDataPath_1
});
NodeScriptLoader._runSoon(function () { return _this._fs.unlink(cachedDataPath_1, function (err) {
if (err) {
opts.onNodeCachedDataError({
errorCode: 'unlink',
path: cachedDataPath_1,
detail: err
});
}
}); }, opts.nodeCachedDataWriteDelay);
}
else if (script.cachedDataProduced) {
// data produced => write cache file
NodeScriptLoader._runSoon(function () { return _this._fs.writeFile(cachedDataPath_1, script.cachedData, function (err) {
if (err) {
opts.onNodeCachedDataError({
errorCode: 'writeFile',
path: cachedDataPath_1,
detail: err
});
}
}); }, opts.nodeCachedDataWriteDelay);
}
});
}
r.call(global, RequireFunc, DefineFunc, vmScriptSrc, _this._path.dirname(scriptSrc));
recorder.record(LoaderEventType.NodeEndEvaluatingScript, scriptSrc);
callback();
});
}
};
NodeScriptLoader.prototype._loadAndEvalScript = function (scriptSrc, vmScriptSrc, contents, options, recorder) {
// create script, run script
recorder.record(LoaderEventType.NodeBeginEvaluatingScript, scriptSrc);
var script = new this._vm.Script(contents, options);
var r = script.runInThisContext(options);
r.call(global, RequireFunc, DefineFunc, vmScriptSrc, this._path.dirname(scriptSrc));
// signal done
recorder.record(LoaderEventType.NodeEndEvaluatingScript, scriptSrc);
return script;
};
NodeScriptLoader.prototype._getCachedDataPath = function (baseDir, filename) {
var hash = this._crypto.createHash('md5').update(filename, 'utf8').digest('hex');
var basename = this._path.basename(filename).replace(/\.js$/, '');
return this._path.join(baseDir, hash + "-" + basename + ".code");
};
NodeScriptLoader._runSoon = function (callback, minTimeout) {
var timeout = minTimeout + Math.ceil(Math.random() * minTimeout);
setTimeout(callback, timeout);
};
NodeScriptLoader._BOM = 0xFEFF;
return NodeScriptLoader;
}());
......@@ -1862,12 +1911,6 @@ var AMDLoader;
RequireFunc.getStats = function () {
return moduleManager.getLoaderEvents();
};
/**
* Non standard extension to fetch checksums
*/
RequireFunc.getChecksums = function () {
return moduleManager.getChecksums();
};
return RequireFunc;
}());
var global = _amdLoaderGlobal, hasPerformanceNow = (global.performance && typeof global.performance.now === 'function'), isWebWorker, isElectronRenderer, isElectronMain, isNode, scriptLoader, moduleManager, loaderAvailableTimestamp;
......
......@@ -71,4 +71,6 @@ export interface IEnvironmentService {
mainIPCHandle: string;
sharedIPCHandle: string;
}
\ No newline at end of file
nodeCachedDataDir: string;
}
......@@ -114,6 +114,9 @@ export class EnvironmentService implements IEnvironmentService {
@memoize
get sharedIPCHandle(): string { return `${getIPCHandlePrefix()}-${pkg.version}-shared${getIPCHandleSuffix()}`; }
@memoize
get nodeCachedDataDir(): string { return path.join(this.userDataPath, 'CachedData', pkg.version); }
constructor(private _args: ParsedArgs, private _execPath: string) { }
}
......@@ -137,4 +140,4 @@ export function parseUserDataDir(args: ParsedArgs, process: NodeJS.Process) {
}
}
return path.resolve(paths.getDefaultUserDataPath(process.platform));
}
\ No newline at end of file
}
......@@ -153,10 +153,15 @@ function main() {
createScript(rootUrl + '/vs/loader.js', function () {
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
window.MonacoEnvironment = {};
const nodeCachedDataErrors = window.MonacoEnvironment.nodeCachedDataErrors = [];
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
recordStats: !!configuration.performance
recordStats: !!configuration.performance,
nodeCachedDataDir: configuration.nodeCachedDataDir,
onNodeCachedDataError: function (err) { nodeCachedDataErrors.push(err) },
});
if (nlsConfig.pseudo) {
......@@ -166,7 +171,6 @@ function main() {
}
// Perf Counters
window.MonacoEnvironment = {};
const timers = window.MonacoEnvironment.timers = {
start: new Date(configuration.isInitialStartup ? configuration.perfStartTime : configuration.perfWindowLoadTime),
isInitialStartup: !!configuration.isInitialStartup,
......@@ -194,4 +198,4 @@ function main() {
});
}
main();
\ No newline at end of file
main();
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { dirname, join } from 'vs/base/common/paths';
import { readdir, rimraf } from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class NodeCachedDataManager {
private _telemetryService: ITelemetryService;
private _environmentService: IEnvironmentService;
private _disposables: IDisposable[] = [];
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IEnvironmentService environmentService: IEnvironmentService
) {
this._telemetryService = telemetryService;
this._environmentService = environmentService;
this._handleCachedDataErrors();
this._manageCachedDataSoon();
}
dispose(): void {
this._disposables = dispose(this._disposables);
}
private _handleCachedDataErrors(): void {
const onNodeCachedDataError = (err) => {
this._telemetryService.publicLog('nodeCachedData', { errorCode: err.errorCode, path: err.path });
};
// handle future and past errors
(<any>self).require.config({ onNodeCachedDataError }, true);
(<any[]>(<any>window).MonacoEnvironment.nodeCachedDataErrors).forEach(onNodeCachedDataError);
delete (<any>window).MonacoEnvironment.nodeCachedDataErrors;
// stop when being disposed
this._disposables.push({
dispose() {
(<any>self).require.config({ onNodeCachedDataError: undefined }, true);
}
});
}
private _manageCachedDataSoon(): void {
// Cached data is stored as user data in directories like `CachedData/1.8.0`.
// This function makes sure to delete cached data from previous versions,
// like`CachedData/1.7.2`.
const {nodeCachedDataDir} = this._environmentService;
if (!nodeCachedDataDir) {
return;
}
let handle = setTimeout(() => {
handle = undefined;
const nodeCachedDataBase = dirname(nodeCachedDataDir);
readdir(nodeCachedDataBase).then(entries => {
const deletes = entries.map(entry => {
const path = join(nodeCachedDataBase, entry);
if (path !== nodeCachedDataDir) {
return rimraf(path);
}
});
return TPromise.join(deletes);
}).done(undefined, onUnexpectedError);
}, 30 * 1000);
this._disposables.push({
dispose() { clearTimeout(handle); }
});
}
}
......@@ -74,6 +74,7 @@ import { MainThreadModeServiceImpl } from 'vs/editor/common/services/modeService
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { CrashReporter } from 'vs/workbench/electron-browser/crashReporter';
import { NodeCachedDataManager } from 'vs/workbench/electron-browser/nodeCachedDataManager';
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
import { ThemeService } from 'vs/workbench/services/themes/electron-browser/themeService';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
......@@ -169,7 +170,12 @@ export class WorkbenchShell {
this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.workspace, this.options, serviceCollection);
this.workbench.startup({
onWorkbenchStarted: (customKeybindingsCount, restoreViewletDuration, restoreEditorsDuration) => {
// run workbench started logic
this.onWorkbenchStarted(customKeybindingsCount, restoreViewletDuration, restoreEditorsDuration);
// start cached data manager
instantiationService.createInstance(NodeCachedDataManager);
}
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册