unicorn Ruby/Rack server user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH] shrink pipes under Linux
@ 2018-08-20 20:30 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2018-08-20 20:30 UTC (permalink / raw)
  To: unicorn-public; +Cc: Eric Wong

We have never had any need for pipes with the default 64K
capacity on Linux.  Our pipes are only used for tiny writes
in signal handlers and to perform parent shutdown detection.

With the current /proc/sys/fs/pipe-user-pages-soft
default, only 1024 pipes can be created by an unprivileged
user before Linux clamps down the pipe size to 4K (a single page)
for newly-created pipes[1].

So avoid penalizing OTHER pipe users who could benefit from the
increased capacity and use only a single page for ourselves.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/pipe.c?h=v4.18#n642
---
 lib/unicorn.rb              | 18 ++++++++++++++++--
 lib/unicorn/http_request.rb |  1 -
 lib/unicorn/launcher.rb     |  2 +-
 test/unit/test_util.rb      | 23 +++++++++++++++++++++++
 4 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index 85e4df1..b6dae36 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -2,6 +2,7 @@
 require 'etc'
 require 'stringio'
 require 'kgio'
+require 'raindrops'
 require 'io/wait'
 
 begin
@@ -113,9 +114,22 @@ def self.log_error(logger, prefix, exc)
     exc.backtrace.each { |line| logger.error(line) }
   end
 
-  # remove this when we only support Ruby >= 2.0
+  F_SETPIPE_SZ = 1031 if RUBY_PLATFORM =~ /linux/
+
   def self.pipe # :nodoc:
-    Kgio::Pipe.new.each { |io| io.close_on_exec = true }
+    Kgio::Pipe.new.each do |io|
+      io.close_on_exec = true  # remove this when we only support Ruby >= 2.0
+
+      # shrink pipes to minimize impact on /proc/sys/fs/pipe-user-pages-soft
+      # limits.
+      if defined?(F_SETPIPE_SZ)
+        begin
+          io.fcntl(F_SETPIPE_SZ, Raindrops::PAGE_SIZE)
+        rescue Errno::EINVAL
+          # old kernel
+        end
+      end
+    end
   end
   # :startdoc:
 end
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index d713b19..8bb884b 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -2,7 +2,6 @@
 # :enddoc:
 # no stable API here
 require 'unicorn_http'
-require 'raindrops'
 
 # TODO: remove redundant names
 Unicorn.const_set(:HttpRequest, Unicorn::HttpParser)
diff --git a/lib/unicorn/launcher.rb b/lib/unicorn/launcher.rb
index 5eafe5b..78e8f39 100644
--- a/lib/unicorn/launcher.rb
+++ b/lib/unicorn/launcher.rb
@@ -31,7 +31,7 @@ def self.daemonize!(options)
       #  \_ parent  - exits immediately ASAP
       #      \_ unicorn master - writes to pipe when ready
 
-      rd, wr = IO.pipe
+      rd, wr = Unicorn.pipe
       grandparent = $$
       if fork
         wr.close # grandparent does not write
diff --git a/test/unit/test_util.rb b/test/unit/test_util.rb
index dc6302e..586fc6c 100644
--- a/test/unit/test_util.rb
+++ b/test/unit/test_util.rb
@@ -102,4 +102,27 @@ def test_reopen_logs_renamed_with_internal_encoding
     }
     tmp.close!
   end
+
+  def test_pipe
+    r, w = Unicorn.pipe
+    assert r
+    assert w
+
+    return if RUBY_PLATFORM =~ /linux/
+
+    f_getpipe_sz = 1032
+    IO.pipe do |a, b|
+      a_sz = a.fcntl(f_getpipe_sz)
+      b_sz = b.fcntl(f_getpipe_sz)
+      assert_kind_of Integer, a_sz
+      r_sz = r.fcntl(f_getpipe_sz)
+      assert_equal Raindrops::PAGE_SIZE, r_sz
+      assert_operator a_sz, :>=, r_sz
+    end
+  rescue Errno::EINVAL
+    # Linux <= 2.6.34
+  ensure
+    w.close
+    r.close
+  end
 end
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2018-08-20 20:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-20 20:30 [PATCH] shrink pipes under Linux Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/unicorn.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).