From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.9 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: mogilefs-client-public@bogomips.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id C7EE61F814 for ; Wed, 4 Nov 2015 21:42:44 +0000 (UTC) From: Eric Wong To: mogilefs-client-public@bogomips.org Subject: [PATCH] socket/pure_ruby: use `:exception=>false' on Ruby 2.1+ Date: Wed, 4 Nov 2015 21:42:44 +0000 Message-Id: <20151104214244.8688-1-e@80x24.org> List-Id: This feature allows us to avoid expensive exceptions when doing non-blocking I/O without relying on horrible hacks like kgio. --- lib/mogilefs/socket/pure_ruby.rb | 87 +++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/lib/mogilefs/socket/pure_ruby.rb b/lib/mogilefs/socket/pure_ruby.rb index e74bbef..d57a7c0 100644 --- a/lib/mogilefs/socket/pure_ruby.rb +++ b/lib/mogilefs/socket/pure_ruby.rb @@ -27,16 +27,6 @@ class MogileFS::Socket < Socket IO.select(nil, [ self ], nil, timeout) end unless self.instance_methods.include?(:wait_writable) # Ruby <2.0.0 - def timed_read(len, dst = "", timeout = 5) - begin - return read_nonblock(len, dst) - rescue Errno::EAGAIN - wait(timeout) or unreadable_socket!(timeout) - rescue EOFError - return - end while true - end - def timed_peek(len, dst, timeout = 5) begin rc = recv_nonblock(len, Socket::MSG_PEEK) @@ -47,26 +37,69 @@ class MogileFS::Socket < Socket dst.replace("") return end while true + rescue EOFError + nil end - def timed_write(buf, timeout = 5) - written = 0 - expect = buf.bytesize - begin - rc = write_nonblock(buf) - return expect if rc == buf.bytesize - written += rc + # write_nonblock and read_nonblock support `exception: false` + if RUBY_VERSION.to_f >= 2.1 + def timed_read(len, dst = "", timeout = 5) + case rc = read_nonblock(len, dst, :exception => false) + when String + return rc + when :wait_readable + wait(timeout) or unreadable_socket!(timeout) + when nil + return + end while true + rescue EOFError + nil + end + + def timed_write(buf, timeout = 5) + written = 0 + expect = buf.bytesize + case rc = write_nonblock(buf, :exception => false) + when Integer + return expect if rc == buf.bytesize + written += rc + buf = buf.byteslice(rc, buf.bytesize) # Ruby 1.9.3+ + when :wait_writable + wait_writable(timeout) or request_truncated!(written, expect, timeout) + end while true + end + else # Ruby 1.8.7 - 2.0.0 + def timed_read(len, dst = "", timeout = 5) + begin + return read_nonblock(len, dst) + rescue Errno::EAGAIN + wait(timeout) or unreadable_socket!(timeout) + rescue EOFError + return + end while true + rescue EOFError + nil + end - if buf.respond_to?(:byteslice) - buf = buf.byteslice(rc, buf.bytesize) - else - if buf.respond_to?(:encoding) && buf.encoding != Encoding::BINARY - buf = buf.dup.force_encoding(Encoding::BINARY) + def timed_write(buf, timeout = 5) + written = 0 + expect = buf.bytesize + begin + rc = write_nonblock(buf) + return expect if rc == buf.bytesize + written += rc + + if buf.respond_to?(:byteslice) # Ruby 1.9.3+ + buf = buf.byteslice(rc, buf.bytesize) + else + if buf.respond_to?(:encoding) && buf.encoding != Encoding::BINARY + buf = buf.dup.force_encoding(Encoding::BINARY) + end + buf = buf.slice(rc, buf.bytesize) end - buf = buf.slice(rc, buf.bytesize) - end - rescue Errno::EAGAIN - wait_writable(timeout) or request_truncated!(written, expect, timeout) - end while true + rescue Errno::EAGAIN + wait_writable(timeout) or request_truncated!(written, expect, timeout) + end while true + end end end -- EW