about summary refs log tree commit homepage
path: root/lib/rainbows/revactor.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-05-03 17:56:00 -0700
committerEric Wong <normalperson@yhbt.net>2010-05-03 17:56:00 -0700
commitde3bcfe3ba9402bd510f7414df1763b6b99dae47 (patch)
tree180526ea73118ed9e3b0cc606684288991875b72 /lib/rainbows/revactor.rb
parent54cae80e543a6f4ca6456fe07b88aba867d215a6 (diff)
downloadrainbows-de3bcfe3ba9402bd510f7414df1763b6b99dae47.tar.gz
WAvoid mucking with Unicorn::TeeInput, since other apps may
depend on that class, so we subclass it as Rainbows::TeeInput
and modify as necessary in worker processes.

For Revactor, remove the special-cased
Rainbows::Revactor::TeeInput class and instead emulate
readpartial for Revactor sockets instead.
Diffstat (limited to 'lib/rainbows/revactor.rb')
-rw-r--r--lib/rainbows/revactor.rb39
1 files changed, 36 insertions, 3 deletions
diff --git a/lib/rainbows/revactor.rb b/lib/rainbows/revactor.rb
index ed08f2c..21fa72f 100644
--- a/lib/rainbows/revactor.rb
+++ b/lib/rainbows/revactor.rb
@@ -21,8 +21,6 @@ module Rainbows
   # concurrency features this model provides.
 
   module Revactor
-    require 'rainbows/revactor/tee_input'
-
     RD_ARGS = {}
 
     include Base
@@ -52,7 +50,7 @@ module Rainbows
         env[Const::CLIENT_IO] = client
         env[Const::RACK_INPUT] = 0 == hp.content_length ?
                  HttpRequest::NULL_IO :
-                 Rainbows::Revactor::TeeInput.new(client, env, hp, buf)
+                 TeeInput.new(PartialSocket.new(client), env, hp, buf)
         env[Const::REMOTE_ADDR] = remote_addr
         response = app.call(env.update(RACK_DEFAULTS))
 
@@ -137,5 +135,40 @@ module Rainbows
       end
     end
 
+    # Revactor Sockets do not implement readpartial, so we emulate just
+    # enough to avoid mucking with TeeInput internals.  Fortunately
+    # this code is not heavily used so we can usually avoid the overhead
+    # of adding a userspace buffer.
+    class PartialSocket < Struct.new(:socket, :rbuf)
+      def initialize(socket)
+        # IO::Buffer is used internally by Rev which Revactor is based on
+        # so we'll always have it available
+        super(socket, IO::Buffer.new)
+      end
+
+      # Revactor socket reads always return an unspecified amount,
+      # sometimes too much
+      def readpartial(length, dst = "")
+        # always check and return from the userspace buffer first
+        rbuf.size > 0 and return dst.replace(rbuf.read(length))
+
+        # read off the socket since there was nothing in rbuf
+        tmp = socket.read
+
+        # we didn't read too much, good, just return it straight back
+        # to avoid needlessly wasting memory bandwidth
+        tmp.size <= length and return dst.replace(tmp)
+
+        # ugh, read returned too much, copy + reread to avoid slicing
+        rbuf << tmp[length, tmp.size]
+        dst.replace(tmp[0, length])
+      end
+
+      # just proxy any remaining methods TeeInput may use
+      def close
+        socket.close
+      end
+    end
+
   end
 end