Browse Source

Do not spin on aceept() with EMFILE

When a server hit EMFILE it would continue to try to accept new connections
from the queue. This patch introduces a timeout of one second where it will
stop trying to accept new files. After the second is over it tries again.

This is a rather serious bug that has been effecting many highly concurrent
programs. It was introduced in 4593c0, version v0.2.0.

TODO: A test for this situation. Currently I test it like this

  termA% cd projects/node
  termA% ulimit -n 256
  termA% ./node benchmark/idle_server.js

  termB% cd projects/node
  termB% ./node benchmark/idle_clients.js

And watch how the server process behaves.
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
0ac2ef924f
  1. 1
      TODO
  2. 24
      lib/net.js

1
TODO

@ -25,3 +25,4 @@
based on size but rather read until EOF into a chain of buffers, then
concat them together.
- process object should be defined in src/node.js not in c++
- Test for EMFILE accept spin bug.

24
lib/net.js

@ -1049,6 +1049,25 @@ function Server (listener) {
self.connections = 0;
self.paused = false;
self.pauseTimeout = 1000;
function pause () {
// We've hit the maximum file limit. What to do?
// Let's try again in 1 second.
self.watcher.stop();
// If we're already paused, don't do another timeout.
if (self.paused) return;
setTimeout(function () {
self.paused = false;
// Make sure we haven't closed in the interim
if (typeof self.fd != 'number') return;
self.watcher.start();
}, self.pauseTimeout);
}
self.watcher = new IOWatcher();
self.watcher.host = self;
self.watcher.callback = function () {
@ -1056,7 +1075,10 @@ function Server (listener) {
try {
var peerInfo = accept(self.fd);
} catch (e) {
if (e.errno == EMFILE) return;
if (e.errno == EMFILE) {
pause();
return;
}
throw e;
}
if (!peerInfo) return;

Loading…
Cancel
Save