mogilefs-client.git  about / heads / tags
MogileFS client library for Ruby
blob 53771c8d882eabec2b507f5b705d3cd8f730b7ae 2405 bytes (raw)
$ git show HEAD:lib/mogilefs/socket_common.rb	# shows this blob on the CLI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 
# -*- encoding: binary -*-
# internal implementation details here, do not rely on this in your code
require "socket"

module MogileFS::SocketCommon
  attr_reader :mogilefs_addr

  def post_init(host, port)
    @mogilefs_addr = "#{host}:#{port}"
    Socket.const_defined?(:TCP_NODELAY) and
      setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
    self
  end

  def unreadable_socket!(timeout)
    raise MogileFS::UnreadableSocketError,
          "#@mogilefs_addr never became readable (timeout=#{timeout.inspect})"
  end

  def request_truncated!(written, expect, timeout)
    timeout = timeout.inspect
    raise MogileFS::RequestTruncatedError,
     "request truncated (sent #{written} expected #{expect} timeout=#{timeout})"
  end

  def timed_gets(timeout = 5)
    unless defined?(@rbuf) && @rbuf
      @rbuf = timed_read(1024, "", timeout) or return # EOF
    end
    begin
      @rbuf.sub!(/\A(.*\n)/, "".freeze) and return $1
      tmp ||= ""
      if timed_read(1024, tmp, timeout)
        @rbuf << tmp
      else
        # EOF, return the last buffered bit even without separatar matching
        # (not ideal for MogileFS, this is an error)
        return @rbuf.empty? ? nil : @rbuf.slice!(0, @rbuf.size)
      end
    end while true
  end

  def read(size, buf = "", timeout = 5)
    timed_read(size, buf, timeout) or return # nil/EOF

    while (remaining = size - buf.bytesize) > 0
      tmp ||= ""
      timed_read(remaining, tmp, timeout) or return buf # truncated
      buf << tmp
    end

    buf # full read
  end

  def readpartial(size, buf = "", timeout = 5)
    timed_read(size, buf, timeout) or raise EOFError, "end of file reached"
  end

  # Workaround for https://bugs.ruby-lang.org/issues/13085
  # (excessive garbage from IO#write)
  # This regression was introduced in Ruby 2.0 (r34847)
  # and it is fixed in Ruby 2.4.1+
  # backport request: https://bugs.ruby-lang.org/issues/13299
  if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' &&
    case RUBY_VERSION
    when '2.0.0',
         '2.1.0'..'2.1.9',
         # we expect 2.2.7 and 2.3.4 to not need this
         '2.2.0'..'2.2.6',
         '2.3.0'..'2.3.3',
         '2.4.0' # 2.4.1 is good!
      def write(buf)
        # Blocking TCP writes would error out long before one day,
        # and MogileFS won't allow file creations which take over a day.
        timed_write(buf, 86400)
      end
    end
  end
end

git clone https://yhbt.net/mogilefs-client.git