Permalink
Browse files

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.
  • Loading branch information...
1 parent 1e932ea commit ad4fb5319bd4e8f5bcb07c41aaa469fe0d87b6e7 @ry ry committed Oct 23, 2010
Showing with 23 additions and 1 deletion.
  1. +23 −1 lib/net.js
View
@@ -1061,14 +1061,36 @@ 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 () {
while (self.fd) {
try {
var peerInfo = accept(self.fd);
} catch (e) {
- if (e.errno == EMFILE) return;
+ if (e.errno == EMFILE) {
+ pause();
+ return;
+ }
throw e;
}
if (!peerInfo) return;

0 comments on commit ad4fb53

Please sign in to comment.