limit maximum splice length to 1 << 30
authorEric Wong <normalperson@yhbt.net>
Wed, 18 May 2011 22:36:52 +0000 (18 15:36 -0700)
committerEric Wong <normalperson@yhbt.net>
Wed, 18 May 2011 22:54:57 +0000 (18 15:54 -0700)
This is the same value haproxy has to work around the same
issue on 64-bit platforms.

ref: a9de333aa58e6cb76f08a50e8ba2c5931184068f in
     http://git.1wt.eu/git/haproxy.git

ext/io_splice/io_splice_ext.c
lib/io/splice.rb
test/test_tcp_splice.rb

index 23cc34f..cbbdbfc 100644 (file)
@@ -15,6 +15,9 @@
 static VALUE sym_EAGAIN;
 #define WAITALL 0x4000000
 
+/* taken from haproxy */
+#define MAX_AT_ONCE (1 << 30)
+
 #ifndef F_LINUX_SPECIFIC_BASE
 #  define F_LINUX_SPECIFIC_BASE 1024
 #endif
@@ -130,6 +133,9 @@ static VALUE nogvl_splice(void *ptr)
 {
        struct splice_args *a = ptr;
 
+       if (a->len > MAX_AT_ONCE)
+               a->len = MAX_AT_ONCE;
+
        return (VALUE)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
                             a->len, a->flags);
 }
@@ -276,6 +282,9 @@ static VALUE nogvl_tee(void *ptr)
 {
        struct tee_args *a = ptr;
 
+       if (a->len > MAX_AT_ONCE)
+               a->len = MAX_AT_ONCE;
+
        return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
 }
 
@@ -682,6 +691,14 @@ void Init_io_splice_ext(void)
         */
        rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));
 
+       /*
+        * The maximum size we're allowed to splice at once.  Larger
+        * sizes will be broken up and retried if the WAITALL flag or
+        * IO::Splice.copy_stream is used.
+        */
+       rb_define_const(mSplice, "MAX_AT_ONCE", SIZET2NUM(MAX_AT_ONCE));
+
+
        if (uname(&utsname) == -1)
                rb_sys_fail("uname");
 
index 84bca5e..65d8ed4 100644 (file)
@@ -49,21 +49,22 @@ module IO::Splice
     if src.stat.pipe? || dst.stat.pipe?
       return full(src, dst, len, src_offset) if len
       rv = 0
-      while n = partial(src, dst, PIPE_CAPA, src_offset)
+      while n = partial(src, dst, MAX_AT_ONCE, src_offset)
         rv += n
         src_offset += n if src_offset
       end
     else
       r, w = tmp = IO.pipe
       close.concat(tmp)
+      rv = 0
       if len
         while len != 0 && n = partial(src, w, len, src_offset)
           src_offset += n if src_offset
+          rv += n
           len -= full(r, dst, n, nil)
         end
       else
-        rv = 0
-        while n = partial(src, w, PIPE_CAPA, src_offset)
+        while n = partial(src, w, MAX_AT_ONCE, src_offset)
           src_offset += n if src_offset
           rv += full(r, dst, n, nil)
         end
index 2ddbfcb..686333c 100644 (file)
@@ -46,4 +46,21 @@ class TestTCPCopyStream < Test::Unit::TestCase
     bytes = IO::Splice.copy_stream(@accept, "/dev/null", expect)
     assert_equal expect, bytes
   end
+
+  def test_mega_splice
+    nr = 2000
+    buf = '0123456789abcdef' * 1024
+    expect = buf.size * nr
+    thr = Thread.new do
+      nr.times { @client.write(buf) }
+      @client.close
+    end
+    size_t_max = if (1 << 30).kind_of?(Bignum)
+      0xffffffff
+    else
+      0xffffffffffffffff
+    end
+    bytes = IO::Splice.copy_stream(@accept, "/dev/null", size_t_max)
+    assert_equal expect, bytes
+  end
 end