Browse Source

Module-level EMFILE handling

All net servers now share the same dummy socket. The ulimit warning is
throttled for all servers.
v0.7.4-release
Jonas Pfenniger 14 years ago
committed by Ryan Dahl
parent
commit
74d0a077ec
  1. 75
      lib/net.js

75
lib/net.js

@ -958,8 +958,8 @@ function Server (/* [ options, ] listener */) {
self.watcher.host = self;
self.watcher.callback = function () {
// Just in case we don't have a dummy fd.
if (!self._dummyFD) self._getDummyFD();
getDummyFD();
if (self._acceptTimer) {
// Somehow the watcher got started again. Need to wait until
// the timer finishes.
@ -972,20 +972,10 @@ function Server (/* [ options, ] listener */) {
} catch (e) {
if (e.errno != EMFILE) throw e;
// Output a warning, but only at most every 5 seconds.
var now = new Date();
if (now - self._lastEMFILEWarning > 5000) {
console.error("(node) Hit max file limit. Increase 'ulimit -n'.");
self._lastEMFILEWarning = now;
}
var acceptCount = 0;
// Gracefully reject pending clients by freeing up a file
// descriptor.
if (self._dummyFD) {
close(self._dummyFD); // Free up an fd
self._dummyFD = null;
rescueEMFILE(function() {
var acceptCount = 0;
// Accept and close the waiting clients one at a time.
// Single threaded programming ftw.
while (true) {
@ -1006,9 +996,8 @@ function Server (/* [ options, ] listener */) {
break;
}
}
// Reacquire the dummy fd
self._getDummyFD();
}
});
return;
}
if (!peerInfo) return;
@ -1131,22 +1120,11 @@ Server.prototype._startWatcher = function () {
this.emit("listening");
};
Server.prototype._getDummyFD = function () {
try {
this._dummyFD = socket("tcp");
} catch (e) {
this._dummyFD = null;
}
};
Server.prototype._doListen = function () {
var self = this;
// Grab a dummy fd for EMFILE conditions.
self._getDummyFD();
self._lastEMFILEWarning = 0;
// Ensure we have a dummy fd for EMFILE conditions.
getDummyFD();
try {
bind(self.fd, arguments[0], arguments[1]);
@ -1189,11 +1167,6 @@ Server.prototype.close = function () {
close(self.fd);
self.fd = null;
if (this._dummyFD) {
close(this._dummyFD);
this._dummyFD = null;
}
if (self.type === "unix") {
fs.unlink(self.path, function () {
self.emit("close");
@ -1202,3 +1175,33 @@ Server.prototype.close = function () {
self.emit("close");
}
};
var dummyFD = null;
var lastEMFILEWarning = 0;
// Ensures to have at least on free file-descriptor free.
// callback should only use 1 file descriptor and close it before end of call
function rescueEMFILE(callback) {
// Output a warning, but only at most every 5 seconds.
var now = new Date();
if (now - lastEMFILEWarning > 5000) {
console.error("(node) Hit max file limit. Increase 'ulimit -n'.");
lastEMFILEWarning = now;
}
if (dummyFD) {
close(dummyFD);
dummyFD = null;
callback();
getDummyFD();
}
}
function getDummyFD() {
if (!dummyFD) {
try {
dummyFD = socket("tcp");
} catch (e) {
dummyFD = null;
}
}
}
Loading…
Cancel
Save