diff options
author | Sokolov Yura 'funny-falcon <funny.falcon@gmail.com> | 2012-06-01 13:42:58 +0400 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2012-06-01 12:15:44 -0700 |
commit | ff27e74a49bf6746ffe74cfc865430221f0bafe0 (patch) | |
tree | 77e55fd96c1d59797732baeceb90130113c38714 /test | |
parent | fa52cc5d0ef7d04b844868e08e2e7ec3c9e3396e (diff) | |
download | kgio-ff27e74a49bf6746ffe74cfc865430221f0bafe0.tar.gz |
Add methods for using writev(2) syscall for sending array of string in a single syscall. This is more efficient than concatenating strings on Ruby side or sending them one by one. `#kgio_trywritev` returns array of strings which are not sent to the socket. If there were objects other than string, they could be converted using `#to_s` method, but this is not strictly applied, cause `#kgio_*writev` tries to write at most `sysconf(_SC_IOV_MAX)` items at once (for Linux its value is 1024). First string of returned array could be part of string from array, so that you should assume it is not in consistent state. `#kgio_writev` semantic differs a bit from `#kgio_write` in term of buffers mutability: currently `#kgio_write` tries to follow string changes made concurrently, but `#kgio_writev` works with array's lightweight copy. Signed-off-by: Eric Wong <normalperson@yhbt.net>
Diffstat (limited to 'test')
-rw-r--r-- | test/lib_read_write.rb | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/test/lib_read_write.rb b/test/lib_read_write.rb index 6f345cb..04d6fc6 100644 --- a/test/lib_read_write.rb +++ b/test/lib_read_write.rb @@ -21,6 +21,14 @@ module LibReadWriteTest assert_nil @wr.kgio_trywrite("") end + def test_writev_empty + assert_nil @wr.kgio_writev([]) + end + + def test_trywritev_empty + assert_nil @wr.kgio_trywritev([]) + end + def test_read_zero assert_equal "", @rd.kgio_read(0) buf = "foo" @@ -116,6 +124,28 @@ module LibReadWriteTest assert false, "should never get here (line:#{__LINE__})" end + def test_writev_closed + @rd.close + begin + loop { @wr.kgio_writev ["HI"] } + rescue Errno::EPIPE, Errno::ECONNRESET => e + assert_equal [], e.backtrace + return + end + assert false, "should never get here (line:#{__LINE__})" + end + + def test_trywritev_closed + @rd.close + begin + loop { @wr.kgio_trywritev ["HI"] } + rescue Errno::EPIPE, Errno::ECONNRESET => e + assert_equal [], e.backtrace + return + end + assert false, "should never get here (line:#{__LINE__})" + end + def test_trywrite_full buf = "\302\251" * 1024 * 1024 buf2 = "" @@ -153,6 +183,43 @@ module LibReadWriteTest assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value end + def test_trywritev_full + buf = ["\302\251" * 128] * 8 * 1024 + buf2 = "" + dig = Digest::SHA1.new + t = Thread.new do + sleep 1 + nr = 0 + begin + dig.update(@rd.readpartial(4096, buf2)) + nr += buf2.size + rescue EOFError + break + rescue => e + end while true + dig.hexdigest + end + 50.times do + wr = buf + begin + rv = @wr.kgio_trywritev(wr) + case rv + when Array + wr = rv + when :wait_readable + assert false, "should never get here line=#{__LINE__}" + when :wait_writable + IO.select(nil, [ @wr ]) + else + wr = false + end + end while wr + end + @wr.close + t.join + assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value + end + def test_write_conv assert_equal nil, @wr.kgio_write(10) assert_equal "10", @rd.kgio_read(2) @@ -214,6 +281,19 @@ module LibReadWriteTest tmp.each { |count| assert_equal nil, count } end + def test_trywritev_return_wait_writable + tmp = [] + tmp << @wr.kgio_trywritev(["HI"]) until tmp[-1] == :wait_writable + assert :wait_writable === tmp[-1] + assert(!(:wait_readable === tmp[-1])) + assert_equal :wait_writable, tmp.pop + assert tmp.size > 0 + penultimate = tmp.pop + assert(penultimate == "I" || penultimate == nil) + assert tmp.size > 0 + tmp.each { |count| assert_equal nil, count } + end + def test_tryread_extra_buf_eagain_clears_buffer tmp = "hello world" rv = @rd.kgio_tryread(2, tmp) @@ -248,6 +328,36 @@ module LibReadWriteTest assert_equal buf, readed end + def test_monster_trywritev + buf, start = [], 0 + while start < RANDOM_BLOB.size + s = RANDOM_BLOB[start, 1000] + start += s.size + buf << s + end + rv = @wr.kgio_trywritev(buf) + assert_kind_of Array, rv + rv = rv.join + assert rv.size < RANDOM_BLOB.size + @rd.nonblock = false + assert_equal(RANDOM_BLOB, @rd.read(RANDOM_BLOB.size - rv.size) + rv) + end + + def test_monster_writev + buf, start = [], 0 + while start < RANDOM_BLOB.size + s = RANDOM_BLOB[start, 10000] + start += s.size + buf << s + end + thr = Thread.new { @wr.kgio_writev(buf) } + @rd.nonblock = false + readed = @rd.read(RANDOM_BLOB.size) + thr.join + assert_nil thr.value + assert_equal RANDOM_BLOB, readed + end + def test_monster_write_wait_writable @wr.instance_variable_set :@nr, 0 def @wr.kgio_wait_writable @@ -256,6 +366,7 @@ module LibReadWriteTest end buf = "." * 1024 * 1024 * 10 thr = Thread.new { @wr.kgio_write(buf) } + Thread.pass until thr.stop? readed = @rd.read(buf.size) thr.join assert_nil thr.value @@ -263,6 +374,23 @@ module LibReadWriteTest assert @wr.instance_variable_get(:@nr) > 0 end + def test_monster_writev_wait_writable + @wr.instance_variable_set :@nr, 0 + def @wr.kgio_wait_writable + @nr += 1 + IO.select(nil, [self]) + end + buf = ["." * 1024] * 1024 * 10 + buf_size = buf.inject(0){|c, s| c + s.size} + thr = Thread.new { @wr.kgio_writev(buf) } + Thread.pass until thr.stop? + readed = @rd.read(buf_size) + thr.join + assert_nil thr.value + assert_equal buf.join, readed + assert @wr.instance_variable_get(:@nr) > 0 + end + def test_wait_readable_ruby_default elapsed = 0 foo = nil |