diff --git a/lib/internal/cluster/child.js b/lib/internal/cluster/child.js index 39e891214ff787..13a22b0186fc28 100644 --- a/lib/internal/cluster/child.js +++ b/lib/internal/cluster/child.js @@ -7,8 +7,8 @@ const { owner_symbol } = require('internal/async_hooks').symbols; const Worker = require('internal/cluster/worker'); const { internal, sendHelper } = require('internal/cluster/utils'); const cluster = new EventEmitter(); -const handles = {}; -const indexes = {}; +const handles = new Map(); +const indexes = new Map(); const noop = () => {}; module.exports = cluster; @@ -62,14 +62,18 @@ cluster._getServer = function(obj, options, cb) { options.addressType, options.fd ].join(':'); - if (indexes[indexesKey] === undefined) - indexes[indexesKey] = 0; + let index = indexes.get(indexesKey); + + if (index === undefined) + index = 0; else - indexes[indexesKey]++; + index++; + + indexes.set(indexesKey, index); const message = util._extend({ act: 'queryServer', - index: indexes[indexesKey], + index, data: null }, options); @@ -107,12 +111,12 @@ function shared(message, handle, indexesKey, cb) { handle.close = function() { send({ act: 'close', key }); - delete handles[key]; - delete indexes[indexesKey]; + handles.delete(key); + indexes.delete(indexesKey); return close.apply(this, arguments); }.bind(handle); - assert(handles[key] === undefined); - handles[key] = handle; + assert(handles.has(key) === false); + handles.set(key, handle); cb(message.errno, handle); } @@ -140,8 +144,8 @@ function rr(message, indexesKey, cb) { return; send({ act: 'close', key }); - delete handles[key]; - delete indexes[indexesKey]; + handles.delete(key); + indexes.delete(indexesKey); key = undefined; } @@ -162,15 +166,15 @@ function rr(message, indexesKey, cb) { handle.getsockname = getsockname; // TCP handles only. } - assert(handles[key] === undefined); - handles[key] = handle; + assert(handles.has(key) === false); + handles.set(key, handle); cb(0, handle); } // Round-robin connection. function onconnection(message, handle) { const key = message.key; - const server = handles[key]; + const server = handles.get(key); const accepted = server !== undefined; send({ ack: message.seq, accepted }); @@ -203,17 +207,16 @@ function _disconnect(masterInitiated) { } } - for (var key in handles) { - const handle = handles[key]; - delete handles[key]; + handles.forEach((handle) => { waitingCount++; if (handle[owner_symbol]) handle[owner_symbol].close(checkWaitingCount); else handle.close(checkWaitingCount); - } + }); + handles.clear(); checkWaitingCount(); } diff --git a/lib/internal/cluster/master.js b/lib/internal/cluster/master.js index 457b3579b12c1c..2eead0b8a3a70a 100644 --- a/lib/internal/cluster/master.js +++ b/lib/internal/cluster/master.js @@ -148,7 +148,7 @@ function removeWorker(worker) { delete cluster.workers[worker.id]; if (keys(cluster.workers).length === 0) { - assert(keys(handles).length === 0, 'Resource leak detected.'); + assert(handles.size === 0, 'Resource leak detected.'); intercom.emit('disconnect'); } } @@ -156,12 +156,10 @@ function removeWorker(worker) { function removeHandlesForWorker(worker) { assert(worker); - for (var key in handles) { - const handle = handles[key]; - + handles.forEach((handle, key) => { if (handle.remove(worker)) - delete handles[key]; - } + handles.delete(key); + }); } cluster.fork = function(env) { @@ -277,7 +275,7 @@ function queryServer(worker, message) { const key = `${message.address}:${message.port}:${message.addressType}:` + `${message.fd}:${message.index}`; - var handle = handles[key]; + var handle = handles.get(key); if (handle === undefined) { let address = message.address; @@ -302,12 +300,13 @@ function queryServer(worker, message) { constructor = SharedHandle; } - handles[key] = handle = new constructor(key, - address, - message.port, - message.addressType, - message.fd, - message.flags); + handle = new constructor(key, + address, + message.port, + message.addressType, + message.fd, + message.flags); + handles.set(key, handle); } if (!handle.data) @@ -319,11 +318,11 @@ function queryServer(worker, message) { errno: errno, key: key, ack: message.seq, - data: handles[key].data + data: handles.get(key).data }, reply); if (errno) - delete handles[key]; // Gives other workers a chance to retry. + handles.delete(key); // Gives other workers a chance to retry. send(worker, reply, handle); }); @@ -346,10 +345,10 @@ function listening(worker, message) { // removed by a prior call to removeHandlesForWorker() so guard against that. function close(worker, message) { const key = message.key; - const handle = handles[key]; + const handle = handles.get(key); if (handle && handle.remove(worker)) - delete handles[key]; + handles.delete(key); } function send(worker, message, handle, cb) { diff --git a/lib/internal/cluster/round_robin_handle.js b/lib/internal/cluster/round_robin_handle.js index e351f433ab8c7e..9f09d9fbf76635 100644 --- a/lib/internal/cluster/round_robin_handle.js +++ b/lib/internal/cluster/round_robin_handle.js @@ -2,7 +2,6 @@ const assert = require('assert'); const net = require('net'); const { sendHelper } = require('internal/cluster/utils'); -const getOwnPropertyNames = Object.getOwnPropertyNames; const { internalBinding } = require('internal/bootstrap/loaders'); const uv = internalBinding('uv'); @@ -10,7 +9,7 @@ module.exports = RoundRobinHandle; function RoundRobinHandle(key, address, port, addressType, fd) { this.key = key; - this.all = {}; + this.all = new Map(); this.free = []; this.handles = []; this.handle = null; @@ -32,8 +31,8 @@ function RoundRobinHandle(key, address, port, addressType, fd) { } RoundRobinHandle.prototype.add = function(worker, send) { - assert(worker.id in this.all === false); - this.all[worker.id] = worker; + assert(this.all.has(worker.id) === false); + this.all.set(worker.id, worker); const done = () => { if (this.handle.getsockname) { @@ -62,16 +61,17 @@ RoundRobinHandle.prototype.add = function(worker, send) { }; RoundRobinHandle.prototype.remove = function(worker) { - if (worker.id in this.all === false) + const existed = this.all.delete(worker.id); + + if (!existed) return false; - delete this.all[worker.id]; const index = this.free.indexOf(worker); if (index !== -1) this.free.splice(index, 1); - if (getOwnPropertyNames(this.all).length !== 0) + if (this.all.size !== 0) return false; for (var handle; handle = this.handles.shift(); handle.close()) @@ -91,7 +91,7 @@ RoundRobinHandle.prototype.distribute = function(err, handle) { }; RoundRobinHandle.prototype.handoff = function(worker) { - if (worker.id in this.all === false) { + if (this.all.has(worker.id) === false) { return; // Worker is closing (or has closed) the server. } diff --git a/lib/internal/cluster/utils.js b/lib/internal/cluster/utils.js index ba72ff90945d3c..c3e14cbb53a721 100644 --- a/lib/internal/cluster/utils.js +++ b/lib/internal/cluster/utils.js @@ -4,10 +4,10 @@ const util = require('util'); module.exports = { sendHelper, internal, - handles: {} // Used in tests. + handles: new Map() // Used in tests. }; -const callbacks = {}; +const callbacks = new Map(); var seq = 0; function sendHelper(proc, message, handle, cb) { @@ -18,7 +18,7 @@ function sendHelper(proc, message, handle, cb) { message = util._extend({ cmd: 'NODE_CLUSTER' }, message); if (typeof cb === 'function') - callbacks[seq] = cb; + callbacks.set(seq, cb); message.seq = seq; seq += 1; @@ -34,9 +34,13 @@ function internal(worker, cb) { var fn = cb; - if (message.ack !== undefined && callbacks[message.ack] !== undefined) { - fn = callbacks[message.ack]; - delete callbacks[message.ack]; + if (message.ack !== undefined) { + const callback = callbacks.get(message.ack); + + if (callback !== undefined) { + fn = callback; + callbacks.delete(message.ack); + } } fn.apply(worker, arguments);