diff --git a/config.template.yaml b/config.template.yaml index 6e1a0b18..9d84aa5d 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -128,3 +128,8 @@ contacts: - name: 'calzoneman' title: 'Developer' email: 'cyzon@cytu.be' + +# If set to true, when the ipThrottle and lastguestlogin rate limiters are cleared +# periodically, the garbage collector will be invoked immediately. +# The server must be invoked with node --expose-gc index.js for this to have any effect. +aggressive-gc: false diff --git a/index.js b/index.js index ad648e8c..127be83f 100644 --- a/index.js +++ b/index.js @@ -40,5 +40,12 @@ function handleLine(line) { if (line === "/reload") { Logger.syslog.log("Reloading config"); Config.load("config.yaml"); + } else if (line === "/gc") { + if (global && global.gc) { + Logger.syslog.log("Running GC"); + global.gc(); + } else { + Logger.syslog.log("Failed to invoke GC: node started without --expose-gc"); + } } } diff --git a/lib/bgtask.js b/lib/bgtask.js index 8cd1dc02..9cf1367e 100644 --- a/lib/bgtask.js +++ b/lib/bgtask.js @@ -69,17 +69,6 @@ function initPasswordResetCleanup(Server) { }, CLEAN_INTERVAL); } -/* Clean out old rate limiters */ -function initIpThrottleCleanup(Server) { - setInterval(function () { - for (var ip in Server.ipThrottle) { - if (Server.ipThrottle[ip].lastTime < Date.now() - 60 * 1000) { - delete Server.ipThrottle[ip]; - } - } - }, 5 * 60 * 1000); -} - function initChannelDumper(Server) { var CHANNEL_SAVE_INTERVAL = parseInt(Config.get("channel-save-interval")) * 60000; @@ -102,7 +91,6 @@ module.exports = function (Server) { init = Server; initStats(Server); initAliasCleanup(Server); - initIpThrottleCleanup(Server); initChannelDumper(Server); initPasswordResetCleanup(Server); }; diff --git a/lib/config.js b/lib/config.js index ecc42496..21e4b6fc 100644 --- a/lib/config.js +++ b/lib/config.js @@ -86,7 +86,8 @@ var defaults = { title: "Developer", email: "cyzon@cytu.be" } - ] + ], + "aggressive-gc": false }; /** diff --git a/lib/io/ioserver.js b/lib/io/ioserver.js index cf021e59..79fe5b6d 100644 --- a/lib/io/ioserver.js +++ b/lib/io/ioserver.js @@ -12,7 +12,6 @@ var CONNECT_RATE = { sustained: 0.1 }; -// Keep track of rate limiting by IP var ipThrottle = {}; // Keep track of number of connections per IP var ipCount = {}; @@ -80,6 +79,10 @@ function handleConnection(sock) { sock.on("disconnect", function () { ipCount[ip]--; + if (ipCount[ip] === 0) { + /* Clear out unnecessary counters to save memory */ + delete ipCount[ip]; + } }); if (!(ip in ipCount)) { @@ -139,3 +142,21 @@ module.exports = { } } }; + +/* Clean out old rate limiters */ +setInterval(function () { + for (var ip in ipThrottle) { + if (ipThrottle[ip].lastTime < Date.now() - 60 * 1000) { + var obj = ipThrottle[ip]; + /* Not strictly necessary, but seems to help the GC out a bit */ + for (var key in obj) { + delete obj[key]; + } + delete ipThrottle[ip]; + } + } + + if (Config.get("aggressive-gc") && global && global.gc) { + global.gc(); + } +}, 5 * 60 * 1000); diff --git a/lib/server.js b/lib/server.js index f3fbe3ec..ee4b276e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const VERSION = "3.0.2"; +const VERSION = "3.0.3"; var singleton = null; var Config = require("./config"); diff --git a/lib/user.js b/lib/user.js index ba8b7230..66eebb44 100644 --- a/lib/user.js +++ b/lib/user.js @@ -604,6 +604,21 @@ User.prototype.guestLogin = function (name) { }); }; +/* Clean out old login throttlers to save memory */ +setInterval(function () { + var delay = Config.get("guest-login-delay"); + for (var ip in lastguestlogin) { + var diff = (Date.now() - lastguestlogin[ip]) / 1000; + if (diff > delay) { + delete lastguestlogin[ip]; + } + } + + if (Config.get("aggressive-gc") && global && global.gc) { + global.gc(); + } +}, 5 * 60 * 1000); + User.prototype.initUserPLCallbacks = function () { require("./userplaylists").init(this); }; diff --git a/package.json b/package.json index b28443d2..e29fbb09 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.0.2", + "version": "3.0.3", "repository": { "url": "http://github.com/calzoneman/sync" },