UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

220 lines (187 loc) 7.57 kB
Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var augmentDefaultFlags = _asyncToGenerator(function* (src, flags) { if (_getDefaultFlags === undefined) { _getDefaultFlags = null; try { // $FlowFB _getDefaultFlags = require('./fb/custom-flags').getDefaultFlags; } catch (e) { // Open-source version } } if (_getDefaultFlags != null) { return flags.concat((yield _getDefaultFlags(src))); } return flags; }); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ var _lruCache2; function _lruCache() { return _lruCache2 = _interopRequireDefault(require('lru-cache')); } var _os2; function _os() { return _os2 = _interopRequireDefault(require('os')); } var _commonsNodePromise2; function _commonsNodePromise() { return _commonsNodePromise2 = require('../../commons-node/promise'); } var _nuclideLogging2; function _nuclideLogging() { return _nuclideLogging2 = require('../../nuclide-logging'); } var _ClangFlagsManager2; function _ClangFlagsManager() { return _ClangFlagsManager2 = _interopRequireDefault(require('./ClangFlagsManager')); } var _ClangServer2; function _ClangServer() { return _ClangServer2 = _interopRequireDefault(require('./ClangServer')); } // Limit the number of active Clang servers. var SERVER_LIMIT = 20; // Limit the total memory usage of all Clang servers. var MEMORY_LIMIT = Math.round((_os2 || _os()).default.totalmem() * 15 / 100); var _getDefaultFlags = undefined; var ClangServerManager = (function () { function ClangServerManager() { _classCallCheck(this, ClangServerManager); this._flagsManager = new (_ClangFlagsManager2 || _ClangFlagsManager()).default(); this._servers = new (_lruCache2 || _lruCache()).default({ max: SERVER_LIMIT, dispose: function dispose(_, val) { val.dispose(); } }); // Avoid race conditions with simultaneous _checkMemoryUsage calls. this._checkMemoryUsage = (0, (_commonsNodePromise2 || _commonsNodePromise()).serializeAsyncCall)(this._checkMemoryUsageImpl.bind(this)); } /** * Spawn one Clang server per translation unit (i.e. source file). * This allows working on multiple files at once, and simplifies per-file state handling. * * TODO(hansonw): We should ideally restart on change for all service requests. * However, restarting (and refetching flags) can take a very long time. * Currently, there's no "status" observable, so we can only provide a busy signal to the user * on diagnostic requests - and hence we only restart on 'compile' requests. */ _createClass(ClangServerManager, [{ key: 'getClangServer', value: _asyncToGenerator(function* (src, contents, defaultFlags, restartIfChanged) { var _this = this; var server = this._servers.get(src); if (server != null) { if (restartIfChanged && this._flagsManager.getFlagsChanged(src)) { this.reset(src); } else { return server; } } var flagsResult = yield this._getFlags(src, defaultFlags); if (flagsResult == null) { return null; } var flags = flagsResult.flags; var usesDefaultFlags = flagsResult.usesDefaultFlags; // Another server could have been created while we were waiting. server = this._servers.get(src); if (server != null) { return server; } server = new (_ClangServer2 || _ClangServer()).default(src, flags, usesDefaultFlags); // Seed with a compile request to ensure fast responses. server.compile(contents).then(function () { return _this._checkMemoryUsage(); }); this._servers.set(src, server); return server; }) // 1. Attempt to get flags from ClangFlagsManager. // 2. Otherwise, fall back to default flags. }, { key: '_getFlags', value: _asyncToGenerator(function* (src, defaultFlags) { var trueFlags = yield this._flagsManager.getFlagsForSrc(src).catch(function (e) { (0, (_nuclideLogging2 || _nuclideLogging()).getLogger)().error('Error getting flags for ' + src + ':', e); return null; }); if (trueFlags != null) { return { flags: trueFlags, usesDefaultFlags: false }; } else if (defaultFlags != null) { return { flags: yield augmentDefaultFlags(src, defaultFlags), usesDefaultFlags: true }; } else { return null; } }) }, { key: 'reset', value: function reset(src) { if (src != null) { this._servers.del(src); } else { this._servers.reset(); } this._flagsManager.reset(); } }, { key: 'dispose', value: function dispose() { this._servers.reset(); this._flagsManager.reset(); } }, { key: '_checkMemoryUsageImpl', value: _asyncToGenerator(function* () { var _this2 = this; var usage = new Map(); yield Promise.all(this._servers.values().map(_asyncToGenerator(function* (server) { var mem = yield server.getMemoryUsage(); usage.set(server, mem); }))); // Servers may have been deleted in the meantime, so calculate the total now. var total = 0; var count = 0; this._servers.forEach(function (server) { var mem = usage.get(server); if (mem) { total += mem; count++; } }); // Remove servers until we're under the memory limit. // Make sure we allow at least one server to stay alive. if (count > 1 && total > MEMORY_LIMIT) { (function () { var toDispose = []; _this2._servers.rforEach(function (server, key) { var mem = usage.get(server); if (mem && count > 1 && total > MEMORY_LIMIT) { total -= mem; count--; toDispose.push(key); } }); toDispose.forEach(function (key) { return _this2._servers.del(key); }); })(); } }) }]); return ClangServerManager; })(); exports.default = ClangServerManager; module.exports = exports.default;