diff options
Diffstat (limited to 'node_modules/jest-worker/build/Farm.js')
-rw-r--r-- | node_modules/jest-worker/build/Farm.js | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/node_modules/jest-worker/build/Farm.js b/node_modules/jest-worker/build/Farm.js new file mode 100644 index 0000000..e29daf5 --- /dev/null +++ b/node_modules/jest-worker/build/Farm.js @@ -0,0 +1,206 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = void 0; + +var _FifoQueue = _interopRequireDefault(require('./FifoQueue')); + +var _types = require('./types'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; +} + +class Farm { + constructor(_numOfWorkers, _callback, options = {}) { + var _options$workerSchedu, _options$taskQueue; + + _defineProperty(this, '_computeWorkerKey', void 0); + + _defineProperty(this, '_workerSchedulingPolicy', void 0); + + _defineProperty(this, '_cacheKeys', Object.create(null)); + + _defineProperty(this, '_locks', []); + + _defineProperty(this, '_offset', 0); + + _defineProperty(this, '_taskQueue', void 0); + + this._numOfWorkers = _numOfWorkers; + this._callback = _callback; + this._computeWorkerKey = options.computeWorkerKey; + this._workerSchedulingPolicy = + (_options$workerSchedu = options.workerSchedulingPolicy) !== null && + _options$workerSchedu !== void 0 + ? _options$workerSchedu + : 'round-robin'; + this._taskQueue = + (_options$taskQueue = options.taskQueue) !== null && + _options$taskQueue !== void 0 + ? _options$taskQueue + : new _FifoQueue.default(); + } + + doWork(method, ...args) { + const customMessageListeners = new Set(); + + const addCustomMessageListener = listener => { + customMessageListeners.add(listener); + return () => { + customMessageListeners.delete(listener); + }; + }; + + const onCustomMessage = message => { + customMessageListeners.forEach(listener => listener(message)); + }; + + const promise = new Promise( // Bind args to this function so it won't reference to the parent scope. + // This prevents a memory leak in v8, because otherwise the function will + // retaine args for the closure. + ((args, resolve, reject) => { + const computeWorkerKey = this._computeWorkerKey; + const request = [_types.CHILD_MESSAGE_CALL, false, method, args]; + let worker = null; + let hash = null; + + if (computeWorkerKey) { + hash = computeWorkerKey.call(this, method, ...args); + worker = hash == null ? null : this._cacheKeys[hash]; + } + + const onStart = worker => { + if (hash != null) { + this._cacheKeys[hash] = worker; + } + }; + + const onEnd = (error, result) => { + customMessageListeners.clear(); + + if (error) { + reject(error); + } else { + resolve(result); + } + }; + + const task = { + onCustomMessage, + onEnd, + onStart, + request + }; + + if (worker) { + this._taskQueue.enqueue(task, worker.getWorkerId()); + + this._process(worker.getWorkerId()); + } else { + this._push(task); + } + }).bind(null, args) + ); + promise.UNSTABLE_onCustomMessage = addCustomMessageListener; + return promise; + } + + _process(workerId) { + if (this._isLocked(workerId)) { + return this; + } + + const task = this._taskQueue.dequeue(workerId); + + if (!task) { + return this; + } + + if (task.request[1]) { + throw new Error('Queue implementation returned processed task'); + } // Reference the task object outside so it won't be retained by onEnd, + // and other properties of the task object, such as task.request can be + // garbage collected. + + const taskOnEnd = task.onEnd; + + const onEnd = (error, result) => { + taskOnEnd(error, result); + + this._unlock(workerId); + + this._process(workerId); + }; + + task.request[1] = true; + + this._lock(workerId); + + this._callback( + workerId, + task.request, + task.onStart, + onEnd, + task.onCustomMessage + ); + + return this; + } + + _push(task) { + this._taskQueue.enqueue(task); + + const offset = this._getNextWorkerOffset(); + + for (let i = 0; i < this._numOfWorkers; i++) { + this._process((offset + i) % this._numOfWorkers); + + if (task.request[1]) { + break; + } + } + + return this; + } + + _getNextWorkerOffset() { + switch (this._workerSchedulingPolicy) { + case 'in-order': + return 0; + + case 'round-robin': + return this._offset++; + } + } + + _lock(workerId) { + this._locks[workerId] = true; + } + + _unlock(workerId) { + this._locks[workerId] = false; + } + + _isLocked(workerId) { + return this._locks[workerId]; + } +} + +exports.default = Farm; |