<commit_before>const os = require('os'),
    cluster = require('cluster'),
    ClusterProcess = require('./cluster_process'),
    WorkerWrapper = require('./worker_wrapper'),
    Port = require('./port'),
    RestartQueue = require('./restart_queue');

/**
 * @constructor
 * @class Master
 * @augments ClusterProcess
 */
class Master extends ClusterProcess {
    constructor() {
        super();

        /**
         * @type {Object}
         * @property {WorkerWrapper} *
         * @public
         * @todo make it private or public immutable
         */
        this.workers = {};

        /**
         * Workers restart queue.
         * @type {RestartQueue}
         * @private
         */
        this._restartQueue = new RestartQueue();

        /**
         * Configuration object to pass to cluster.setupMaster()
         * @type {Object}
         * @private
         */
        this._masterOpts = {};

        this.id = 0;
        this.wid = 0;
        this.pid = process.pid;

        this.on('worker state', this._cleanupUnixSockets.bind(this));
        this.on('worker exit', this._checkWorkersAlive.bind(this));

        // @todo make it optional?
        process.on('SIGINT', this._onSignalQuit.bind(this));
        process.on('SIGQUIT', this._onSignalQuit.bind(this));
    }

    /**
     * Allows same object structure as cluster.setupMaster().
     * This function must be used instead of cluster.setupMaster(),
     * because all calls of cluster.setupMaster() ignored, except first one.
     * An instance of Master will call it, when running.
     * @param {Object} opts
     * @see {@link http://nodejs.org/api/cluster.html#cluster_cluster_setupmaster_settings}
     */
    setup(opts) {
        Object.assign(this._masterOpts, opts);
    }

    /**
     * SIGINT and SIGQUIT handler
     * @private
     */
    _onSignalQuit() {
        this
            .once('shutdown', function() {
                process.exit(0);
            })
            .shutdown();
    }

    /**
     * Remove not used unix socket before worker will try to listen it.
     * @param {WorkerWrapper} worker
     * @param {WorkerWrapperState} state
     * @private
     */
    _cleanupUnixSockets(worker, state) {
        const port = worker.options.port;

        if (this._restartQueue.has(worker) ||
            state !== WorkerWrapper.STATES.LAUNCHING ||
            port.family !== Port.UNIX) {
            return;
        }

        const self = this,
            inUse = this.getWorkersArray().some(function(w) {
                return worker.wid !== w.wid &&
                    w.isRunning() &&
                    port.isEqualTo(w.options.port);
            });

        if (!inUse) {
            port.unlink(function(err) {
                if (err) {
                    self.emit('error', err);
                }
            });
        }
    }

    /**
     * Check for alive workers, if no one here, then emit "shutdown".
     * @private
     */
    _checkWorkersAlive() {
        const workers = this.getWorkersArray(),
            alive = workers.reduce(function(count, w) {
                return w.dead ? count - 1 : count;
            }, workers.length);

        if (alive === 0) {
            this.emit('shutdown');
        }
    }

    /**
     * Repeat WorkerWrapper events on Master and add 'worker ' prefix to event names
     * so for example 'online' became 'worker online'
     * @private
     * @param {WorkerWrapper} worker
     */
    _proxyWorkerEvents(worker) {
        WorkerWrapper.EVENTS
            .forEach(function(eventName) {
                worker.on(eventName, this.emit.bind(this, 'worker ' + eventName, worker));
            }, this);
    }

    /**
     * @returns {WorkerWrapper[]} workers array
     */
    getWorkersArray() {
        if (!this._workersArrayCache) {
            this._workersArrayCache = Object.keys(this.workers).map(function(wid) {
                return this.workers[wid];
            }, this);
        }

        return this._workersArrayCache;<commit_msg>Simplify getWorkersArray using Object.values<commit_after>const os = require('os'),
    cluster = require('cluster'),
    ClusterProcess = require('./cluster_process'),
    WorkerWrapper = require('./worker_wrapper'),
    Port = require('./port'),
    RestartQueue = require('./restart_queue');

/**
 * @constructor
 * @class Master
 * @augments ClusterProcess
 */
class Master extends ClusterProcess {
    constructor() {
        super();

        /**
         * @type {Object}
         * @property {WorkerWrapper} *
         * @public
         * @todo make it private or public immutable
         */
        this.workers = {};

        /**
         * Workers restart queue.
         * @type {RestartQueue}
         * @private
         */
        this._restartQueue = new RestartQueue();

        /**
         * Configuration object to pass to cluster.setupMaster()
         * @type {Object}
         * @private
         */
        this._masterOpts = {};

        this.id = 0;
        this.wid = 0;
        this.pid = process.pid;

        this.on('worker state', this._cleanupUnixSockets.bind(this));
        this.on('worker exit', this._checkWorkersAlive.bind(this));

        // @todo make it optional?
        process.on('SIGINT', this._onSignalQuit.bind(this));
        process.on('SIGQUIT', this._onSignalQuit.bind(this));
    }

    /**
     * Allows same object structure as cluster.setupMaster().
     * This function must be used instead of cluster.setupMaster(),
     * because all calls of cluster.setupMaster() ignored, except first one.
     * An instance of Master will call it, when running.
     * @param {Object} opts
     * @see {@link http://nodejs.org/api/cluster.html#cluster_cluster_setupmaster_settings}
     */
    setup(opts) {
        Object.assign(this._masterOpts, opts);
    }

    /**
     * SIGINT and SIGQUIT handler
     * @private
     */
    _onSignalQuit() {
        this
            .once('shutdown', function() {
                process.exit(0);
            })
            .shutdown();
    }

    /**
     * Remove not used unix socket before worker will try to listen it.
     * @param {WorkerWrapper} worker
     * @param {WorkerWrapperState} state
     * @private
     */
    _cleanupUnixSockets(worker, state) {
        const port = worker.options.port;

        if (this._restartQueue.has(worker) ||
            state !== WorkerWrapper.STATES.LAUNCHING ||
            port.family !== Port.UNIX) {
            return;
        }

        const self = this,
            inUse = this.getWorkersArray().some(function(w) {
                return worker.wid !== w.wid &&
                    w.isRunning() &&
                    port.isEqualTo(w.options.port);
            });

        if (!inUse) {
            port.unlink(function(err) {
                if (err) {
                    self.emit('error', err);
                }
            });
        }
    }

    /**
     * Check for alive workers, if no one here, then emit "shutdown".
     * @private
     */
    _checkWorkersAlive() {
        const workers = this.getWorkersArray(),
            alive = workers.reduce(function(count, w) {
                return w.dead ? count - 1 : count;
            }, workers.length);

        if (alive === 0) {
            this.emit('shutdown');
        }
    }

    /**
     * Repeat WorkerWrapper events on Master and add 'worker ' prefix to event names
     * so for example 'online' became 'worker online'
     * @private
     * @param {WorkerWrapper} worker
     */
    _proxyWorkerEvents(worker) {
        WorkerWrapper.EVENTS
            .forEach(function(eventName) {
                worker.on(eventName, this.emit.bind(this, 'worker ' + eventName, worker));
            }, this);
    }

    /**
     * @returns {WorkerWrapper[]} workers array
     */
    getWorkersArray() {
        if (!this._workersArrayCache) {
            this._workersArrayCache = Object.values(this.workers);
        }

        return this._workersArrayCache;
{'fraction_non_alphanumeric': 0.1264066016504126, 'fraction_numerical': 0.001250312578144536, 'mean_word_length': 1.7755031228313671, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1916564', 'n_tokens_mistral': 2255, 'n_tokens_neox': 2184, 'n_words': 501}