Ruby mogilefs-client 3.12.2
[ruby-mogilefs-client.git] / lib / mogilefs / socket_common.rb
blob53771c8d882eabec2b507f5b705d3cd8f730b7ae
1 # -*- encoding: binary -*-
2 # internal implementation details here, do not rely on this in your code
3 require "socket"
5 module MogileFS::SocketCommon
6   attr_reader :mogilefs_addr
8   def post_init(host, port)
9     @mogilefs_addr = "#{host}:#{port}"
10     Socket.const_defined?(:TCP_NODELAY) and
11       setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
12     self
13   end
15   def unreadable_socket!(timeout)
16     raise MogileFS::UnreadableSocketError,
17           "#@mogilefs_addr never became readable (timeout=#{timeout.inspect})"
18   end
20   def request_truncated!(written, expect, timeout)
21     timeout = timeout.inspect
22     raise MogileFS::RequestTruncatedError,
23      "request truncated (sent #{written} expected #{expect} timeout=#{timeout})"
24   end
26   def timed_gets(timeout = 5)
27     unless defined?(@rbuf) && @rbuf
28       @rbuf = timed_read(1024, "", timeout) or return # EOF
29     end
30     begin
31       @rbuf.sub!(/\A(.*\n)/, "".freeze) and return $1
32       tmp ||= ""
33       if timed_read(1024, tmp, timeout)
34         @rbuf << tmp
35       else
36         # EOF, return the last buffered bit even without separatar matching
37         # (not ideal for MogileFS, this is an error)
38         return @rbuf.empty? ? nil : @rbuf.slice!(0, @rbuf.size)
39       end
40     end while true
41   end
43   def read(size, buf = "", timeout = 5)
44     timed_read(size, buf, timeout) or return # nil/EOF
46     while (remaining = size - buf.bytesize) > 0
47       tmp ||= ""
48       timed_read(remaining, tmp, timeout) or return buf # truncated
49       buf << tmp
50     end
52     buf # full read
53   end
55   def readpartial(size, buf = "", timeout = 5)
56     timed_read(size, buf, timeout) or raise EOFError, "end of file reached"
57   end
59   # Workaround for https://bugs.ruby-lang.org/issues/13085
60   # (excessive garbage from IO#write)
61   # This regression was introduced in Ruby 2.0 (r34847)
62   # and it is fixed in Ruby 2.4.1+
63   # backport request: https://bugs.ruby-lang.org/issues/13299
64   if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' &&
65     case RUBY_VERSION
66     when '2.0.0',
67          '2.1.0'..'2.1.9',
68          # we expect 2.2.7 and 2.3.4 to not need this
69          '2.2.0'..'2.2.6',
70          '2.3.0'..'2.3.3',
71          '2.4.0' # 2.4.1 is good!
72       def write(buf)
73         # Blocking TCP writes would error out long before one day,
74         # and MogileFS won't allow file creations which take over a day.
75         timed_write(buf, 86400)
76       end
77     end
78   end
79 end