From: Eric Wong Date: Wed, 18 May 2011 22:36:52 +0000 (-0700) Subject: limit maximum splice length to 1 << 30 X-Git-Tag: v4.2.0~5 X-Git-Url: https://repo.or.cz/w/ruby_io_splice.git/commitdiff_plain/a2ae924fb1c372cc559a59feca40780a9a37ba33 limit maximum splice length to 1 << 30 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 --- diff --git a/ext/io_splice/io_splice_ext.c b/ext/io_splice/io_splice_ext.c index 23cc34f..cbbdbfc 100644 --- a/ext/io_splice/io_splice_ext.c +++ b/ext/io_splice/io_splice_ext.c @@ -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"); diff --git a/lib/io/splice.rb b/lib/io/splice.rb index 84bca5e..65d8ed4 100644 --- a/lib/io/splice.rb +++ b/lib/io/splice.rb @@ -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 diff --git a/test/test_tcp_splice.rb b/test/test_tcp_splice.rb index 2ddbfcb..686333c 100644 --- a/test/test_tcp_splice.rb +++ b/test/test_tcp_splice.rb @@ -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