From 39b178cdebe275cbc8ce19cf269bea7cd15ff4ca Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 4 Jul 2010 22:16:52 +0000 Subject: refactor response body handling for sendfile(2) This hopefully allows the "sendfile" gem to be required anywhere in the Rainbows!/Unicorn config file, and not have to be required via RUBYOPT or the '-r' command-line switch. We also modularize HttpResponse and avoids singleton methods in the response path. This (hopefully) makes it easier for individual concurrency models to share code and override individual methods. --- lib/rainbows/fiber/base.rb | 32 +++++--------------------------- lib/rainbows/fiber/body.rb | 36 ++++++++++++++++++++++++++++++++++++ lib/rainbows/fiber/rev.rb | 3 ++- 3 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 lib/rainbows/fiber/body.rb (limited to 'lib/rainbows/fiber') diff --git a/lib/rainbows/fiber/base.rb b/lib/rainbows/fiber/base.rb index 7e39441..9ac3b72 100644 --- a/lib/rainbows/fiber/base.rb +++ b/lib/rainbows/fiber/base.rb @@ -72,33 +72,6 @@ module Rainbows max.nil? || max > (now + 1) ? 1 : max - now end - # TODO: IO.splice under Linux - alias write_body_stream write_body_each - - # the sendfile 1.0.0+ gem includes IO#sendfile_nonblock - if ::IO.method_defined?(:sendfile_nonblock) - def write_body_path(client, body) - file = Rainbows.body_to_io(body) - if file.stat.file? - sock, off = client.to_io, 0 - begin - off += sock.sendfile_nonblock(file, off, 0x10000) - rescue Errno::EAGAIN - client.wait_writable - rescue EOFError - break - rescue => e - Rainbows::Error.app(e) - break - end while true - else - write_body_stream(client, body) - end - end - else - alias write_body write_body_each - end - def wait_headers_readable(client) io = client.to_io expire = nil @@ -120,6 +93,11 @@ module Rainbows ZZ.delete(client.f) end + def self.setup(klass, app) + require 'rainbows/fiber/body' + klass.__send__(:include, Rainbows::Fiber::Body) + self.const_set(:APP, app) + end end end end diff --git a/lib/rainbows/fiber/body.rb b/lib/rainbows/fiber/body.rb new file mode 100644 index 0000000..cd6c55c --- /dev/null +++ b/lib/rainbows/fiber/body.rb @@ -0,0 +1,36 @@ +# -*- encoding: binary -*- +# non-portable body handling for Fiber-based concurrency goes here +# this module is required and included in worker processes only +# this is meant to be included _after_ Rainbows::HttpResponse::Body +module Rainbows::Fiber::Body # :nodoc: + + # TODO non-blocking splice(2) under Linux + ALIASES = { + :write_body_stream => :write_body_each + } + + # the sendfile 1.0.0+ gem includes IO#sendfile_nonblock + if ::IO.method_defined?(:sendfile_nonblock) + def write_body_file(client, body) + sock, off = client.to_io, 0 + begin + off += sock.sendfile_nonblock(body, off, 0x10000) + rescue Errno::EAGAIN + client.wait_writable + rescue EOFError + break + rescue => e + Rainbows::Error.app(e) + break + end while true + end + else + ALIASES[:write_body] = :write_body_each + end + + def self.included(klass) + ALIASES.each do |new_method, orig_method| + klass.__send__(:alias_method, new_method, orig_method) + end + end +end diff --git a/lib/rainbows/fiber/rev.rb b/lib/rainbows/fiber/rev.rb index b8ec56b..2e8f076 100644 --- a/lib/rainbows/fiber/rev.rb +++ b/lib/rainbows/fiber/rev.rb @@ -52,6 +52,7 @@ module Rainbows::Fiber include Unicorn include Rainbows include Rainbows::Const + include Rainbows::HttpResponse FIO = Rainbows::Fiber::IO def to_io @@ -99,7 +100,7 @@ module Rainbows::Fiber alive = hp.keepalive? && G.alive out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if hp.headers? - HttpResponse.write(client, response, out) + write_response(client, response, out) end while alive and hp.reset.nil? and env.clear rescue => e Error.write(io, e) -- cgit v1.2.3-24-ge0c7