mogilefs-client 2.2.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.document +11 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +4 -0
  4. data/.wrongdoc.yml +5 -0
  5. data/GIT-VERSION-GEN +28 -0
  6. data/GNUmakefile +44 -0
  7. data/HACKING +33 -0
  8. data/{History.txt → History} +0 -1
  9. data/{LICENSE.txt → LICENSE} +0 -1
  10. data/Manifest.txt +34 -7
  11. data/README +51 -0
  12. data/Rakefile +11 -11
  13. data/TODO +10 -0
  14. data/bin/mog +109 -68
  15. data/examples/mogstored_rack.rb +189 -0
  16. data/lib/mogilefs.rb +56 -17
  17. data/lib/mogilefs/admin.rb +128 -62
  18. data/lib/mogilefs/backend.rb +205 -95
  19. data/lib/mogilefs/bigfile.rb +54 -70
  20. data/lib/mogilefs/bigfile/filter.rb +58 -0
  21. data/lib/mogilefs/chunker.rb +30 -0
  22. data/lib/mogilefs/client.rb +0 -2
  23. data/lib/mogilefs/copy_stream.rb +30 -0
  24. data/lib/mogilefs/http_file.rb +175 -0
  25. data/lib/mogilefs/http_reader.rb +79 -0
  26. data/lib/mogilefs/mogilefs.rb +242 -148
  27. data/lib/mogilefs/mysql.rb +3 -4
  28. data/lib/mogilefs/paths_size.rb +24 -0
  29. data/lib/mogilefs/pool.rb +0 -1
  30. data/lib/mogilefs/socket.rb +9 -0
  31. data/lib/mogilefs/socket/kgio.rb +55 -0
  32. data/lib/mogilefs/socket/pure_ruby.rb +70 -0
  33. data/lib/mogilefs/socket_common.rb +58 -0
  34. data/lib/mogilefs/util.rb +6 -169
  35. data/test/aggregate.rb +11 -11
  36. data/test/exec.rb +72 -0
  37. data/test/fresh.rb +222 -0
  38. data/test/integration.rb +43 -0
  39. data/test/setup.rb +1 -0
  40. data/test/socket_test.rb +98 -0
  41. data/test/test_admin.rb +14 -37
  42. data/test/test_backend.rb +50 -107
  43. data/test/test_bigfile.rb +2 -2
  44. data/test/test_db_backend.rb +1 -2
  45. data/test/test_fresh.rb +8 -0
  46. data/test/test_http_reader.rb +34 -0
  47. data/test/test_mogilefs.rb +278 -98
  48. data/test/test_mogilefs_integration.rb +174 -0
  49. data/test/test_mogilefs_integration_large_pipe.rb +62 -0
  50. data/test/test_mogilefs_integration_list_keys.rb +40 -0
  51. data/test/test_mogilefs_socket_kgio.rb +11 -0
  52. data/test/test_mogilefs_socket_pure.rb +7 -0
  53. data/test/test_mogstored_rack.rb +89 -0
  54. data/test/test_mogtool_bigfile.rb +116 -0
  55. data/test/test_mysql.rb +1 -2
  56. data/test/test_pool.rb +1 -1
  57. data/test/test_unit_mogstored_rack.rb +72 -0
  58. metadata +76 -54
  59. data/README.txt +0 -80
  60. data/lib/mogilefs/httpfile.rb +0 -157
  61. data/lib/mogilefs/network.rb +0 -107
  62. data/test/test_network.rb +0 -56
  63. data/test/test_util.rb +0 -121
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
- require 'mogilefs'
3
- require 'mogilefs/backend' # for the exceptions
4
-
2
+ # Consider this deprecated, to be removed at some point...
3
+ #
5
4
  # read-only interface that can be a backend for MogileFS::MogileFS
6
5
  #
7
6
  # This provides direct, read-only access to any slave MySQL database to
@@ -29,7 +28,7 @@ class MogileFS::Mysql
29
28
  ##
30
29
  # Lists keys starting with +prefix+ follwing +after+ up to +limit+. If
31
30
  # +after+ is nil the list starts at the beginning.
32
- def _list_keys(domain, prefix = '', after = '', limit = 1000, &block)
31
+ def _list_keys(domain, prefix = '', after = '', limit = 1000)
33
32
  # this code is based on server/lib/MogileFS/Worker/Query.pm
34
33
  dmid = get_dmid(domain)
35
34
 
@@ -0,0 +1,24 @@
1
+ # -*- encoding: binary -*-
2
+ # This is only a hack for old MogileFS installs that didn't have file_info
3
+ require "net/http"
4
+ require "uri"
5
+ module MogileFS::PathsSize
6
+ def self.call(paths)
7
+ errors = {}
8
+ paths.each do |path|
9
+ uri = URI.parse(path)
10
+ begin
11
+ case r = Net::HTTP.start(uri.host, uri.port) { |x| x.head(uri.path) }
12
+ when Net::HTTPOK
13
+ return r["Content-Length"].to_i
14
+ else
15
+ errors[path] = r
16
+ end
17
+ rescue => err
18
+ errors[path] = err
19
+ end
20
+ end
21
+ errors = errors.map { |path,err| "#{path} - #{err.message} (#{err.class})" }
22
+ raise MogileFS::Error, "all paths failed with HEAD: #{errors.join(', ')}"
23
+ end
24
+ end
data/lib/mogilefs/pool.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'thread'
3
- require 'mogilefs'
4
3
 
5
4
  class MogileFS::Pool
6
5
 
@@ -0,0 +1,9 @@
1
+ # -*- encoding: binary -*-
2
+ # internal implementation details here, do not rely on this in your code
3
+ require "mogilefs/socket_common"
4
+ begin
5
+ raise LoadError, "testing pure Ruby version" if ENV["MOGILEFS_CLIENT_PURE"]
6
+ require "mogilefs/socket/kgio"
7
+ rescue LoadError
8
+ require "mogilefs/socket/pure_ruby"
9
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding: binary -*-
2
+ # internal implementation details here, do not rely on them in your code
3
+ require "kgio"
4
+
5
+ class MogileFS::Socket < Kgio::Socket
6
+ include MogileFS::SocketCommon
7
+
8
+ def self.start(host, port)
9
+ sock = super(Socket.sockaddr_in(port, host))
10
+ sock.post_init(host, port)
11
+ end
12
+
13
+ def self.tcp(host, port, timeout = 5)
14
+ sock = start(host, port)
15
+ unless sock.kgio_wait_writable(timeout)
16
+ sock.close
17
+ raise MogileFS::Timeout, 'socket connect timeout'
18
+ end
19
+ sock
20
+ end
21
+
22
+ def timed_read(len, dst = "", timeout = 5)
23
+ case rc = kgio_tryread(len, dst)
24
+ when :wait_readable
25
+ kgio_wait_readable(timeout) or unreadable_socket!
26
+ else
27
+ return rc
28
+ end while true
29
+ end
30
+
31
+ def timed_peek(len, dst, timeout = 5)
32
+ case rc = kgio_trypeek(len, dst)
33
+ when :wait_readable
34
+ kgio_wait_readable(timeout) or unreadable_socket!
35
+ else
36
+ return rc
37
+ end while true
38
+ end
39
+
40
+ def timed_write(buf, timeout = 5)
41
+ written = 0
42
+ expect = buf.bytesize
43
+ case rc = kgio_trywrite(buf)
44
+ when :wait_writable
45
+ kgio_wait_writable(timeout) or request_truncated!(written, expect)
46
+ when String
47
+ written += expect - rc.bytesize
48
+ buf = rc
49
+ else
50
+ return expect
51
+ end while true
52
+ end
53
+
54
+ alias write timed_write
55
+ end
@@ -0,0 +1,70 @@
1
+ # -*- encoding: binary -*-
2
+ # internal implementation details here, do not rely on them in your code
3
+
4
+ class MogileFS::Socket < Socket
5
+ include MogileFS::SocketCommon
6
+
7
+ def self.start(host, port)
8
+ sock = new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
9
+ begin
10
+ sock.connect_nonblock(sockaddr_in(port, host))
11
+ rescue Errno::EINPROGRESS
12
+ end
13
+ sock.post_init(host, port)
14
+ end
15
+
16
+ def self.tcp(host, port, timeout = 5)
17
+ sock = start(host, port)
18
+ unless IO.select(nil, [ sock ], nil, timeout)
19
+ sock.close
20
+ raise MogileFS::Timeout, 'socket connect timeout'
21
+ end
22
+ sock
23
+ end
24
+
25
+ def timed_read(len, dst = "", timeout = 5)
26
+ begin
27
+ IO.select([self], nil, nil, timeout) or unreadable_socket!
28
+ return read_nonblock(len, dst)
29
+ rescue Errno::EAGAIN
30
+ rescue EOFError
31
+ return
32
+ end while true
33
+ end
34
+
35
+ def timed_peek(len, dst, timeout = 5)
36
+ begin
37
+ IO.select([self], nil, nil, timeout) or unreadable_socket!
38
+ rc = recv_nonblock(len, Socket::MSG_PEEK)
39
+ return rc.empty? ? nil : dst.replace(rc)
40
+ rescue Errno::EAGAIN
41
+ rescue EOFError
42
+ dst.replace("")
43
+ return
44
+ end while true
45
+ end
46
+
47
+ def timed_write(buf, timeout = 5)
48
+ written = 0
49
+ expect = buf.bytesize
50
+ begin
51
+ rc = write_nonblock(buf)
52
+ return expect if rc == buf.bytesize
53
+ written += rc
54
+
55
+ if buf.respond_to?(:byteslice)
56
+ buf = buf.byteslice(rc, buf.bytesize)
57
+ else
58
+ if buf.respond_to?(:encoding) && buf.encoding != Encoding::BINARY
59
+ buf = buf.dup.force_encoding(Encoding::BINARY)
60
+ end
61
+ buf = buf.slice(rc, buf.bytesize)
62
+ end
63
+ rescue Errno::EAGAIN
64
+ IO.select(nil, [self], nil, timeout) or
65
+ request_truncated!(written, expect)
66
+ end while true
67
+ end
68
+
69
+ alias write timed_write
70
+ end
@@ -0,0 +1,58 @@
1
+ # -*- encoding: binary -*-
2
+ # internal implementation details here, do not rely on this in your code
3
+ require "socket"
4
+
5
+ module MogileFS::SocketCommon
6
+ attr_reader :mogilefs_addr
7
+
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
14
+
15
+ def unreadable_socket!
16
+ raise MogileFS::UnreadableSocketError,
17
+ "#@mogilefs_addr never became readable"
18
+ end
19
+
20
+ def request_truncated!(written, expect)
21
+ raise MogileFS::RequestTruncatedError,
22
+ "request truncated (sent #{written} expected #{expect})"
23
+ end
24
+
25
+ SEP_RE = /\A(.*?#{Regexp.escape("\n")})/
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!(SEP_RE, "") 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 SEP_RE 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
42
+
43
+ def read(size, buf = "", timeout = 5)
44
+ timed_read(size, buf, timeout) or return # nil/EOF
45
+
46
+ while size > buf.bytesize
47
+ tmp ||= ""
48
+ timed_read(size - buf.bytesize, tmp, timeout) or return buf # truncated
49
+ buf << tmp
50
+ end
51
+
52
+ buf # full read
53
+ end
54
+
55
+ def readpartial(size, buf = "", timeout = 5)
56
+ timed_read(size, buf, timeout) or raise EOFError, "end of file reached"
57
+ end
58
+ end
data/lib/mogilefs/util.rb CHANGED
@@ -1,96 +1,13 @@
1
1
  # -*- encoding: binary -*-
2
- require 'mogilefs'
3
- require 'socket'
4
2
 
5
3
  module MogileFS::Util
6
4
 
7
- CHUNK_SIZE = 65536
8
-
9
- # for copying large files while avoiding GC thrashing as much as possible
10
- # writes the contents of io_rd into io_wr, running through filter if
11
- # it is a Proc object. The filter proc must respond to a string
12
- # argument (and return a string) and to nil (possibly returning a
13
- # string or nil). This can be used to filter I/O through an
14
- # Zlib::Inflate or Digest::MD5 object
15
- def sysrwloop(io_rd, io_wr, filter = nil)
16
- copied = 0
17
- # avoid making sysread repeatedly allocate a new String
18
- # This is not well-documented, but both read/sysread can take
19
- # an optional second argument to use as the buffer to avoid
20
- # GC overhead of creating new strings in a loop
21
- buf = ' ' * CHUNK_SIZE # preallocate to avoid GC thrashing
22
- io_rd.flush rescue nil # flush may be needed for sockets/pipes, be safe
23
- io_wr.flush
24
- io_rd.sync = io_wr.sync = true
25
- loop do
26
- b = begin
27
- io_rd.sysread(CHUNK_SIZE, buf)
28
- rescue Errno::EAGAIN, Errno::EINTR
29
- IO.select([io_rd], nil, nil, nil)
30
- retry
31
- rescue EOFError
32
- break
33
- end
34
- b = filter.call(b) if filter
35
- copied += syswrite_full(io_wr, b)
36
- end
37
-
38
- # filter must take nil as a possible argument to indicate EOF
39
- if filter
40
- b = filter.call(nil)
41
- copied += syswrite_full(io_wr, b) if b && b.length > 0
42
- end
43
- copied
44
- end # sysrwloop
45
-
46
- # writes the contents of buf to io_wr in full w/o blocking
47
- def syswrite_full(io_wr, buf, timeout = nil)
48
- written = 0
49
- loop do
50
- begin
51
- w = io_wr.syswrite(buf)
52
- written += w
53
- return written if w == buf.size
54
- buf = buf[w..-1]
55
-
56
- # a short syswrite means the next syswrite will likely block
57
- # inside the interpreter. so force an IO.select on it so we can
58
- # timeout there if one was specified
59
- raise Errno::EAGAIN if timeout
60
- rescue Errno::EAGAIN, Errno::EINTR
61
- t0 = Time.now if timeout
62
- IO.select(nil, [io_wr], nil, timeout)
63
- if timeout && ((timeout -= (Time.now - t0)) < 0)
64
- raise MogileFS::Timeout, 'syswrite_full timeout'
65
- end
66
- end
67
- end
68
- # should never get here
69
- end
70
-
71
- def sysread_full(io_rd, size, timeout = nil, full_timeout = false)
72
- tmp = [] # avoid expensive string concatenation with every loop iteration
73
- reader = io_rd.method(timeout ? :read_nonblock : :sysread)
74
- begin
75
- while size > 0
76
- tmp << reader.call(size)
77
- size -= tmp.last.size
78
- end
79
- rescue Errno::EAGAIN, Errno::EINTR
80
- t0 = Time.now
81
- r = IO.select([ io_rd ], nil, nil, timeout)
82
- if timeout
83
- timeout -= (Time.now - t0) if full_timeout
84
- if !(r && r[0]) || timeout < 0
85
- raise MogileFS::Timeout, 'sysread_full timeout'
86
- end
87
- end
88
- retry
89
- rescue EOFError
90
- end
91
- tmp.join('')
92
- end
93
-
5
+ # MogileFS::Util::StoreContent allows you to roll your own method
6
+ # of streaming data on an upload (instead of using a string or file)
7
+ #
8
+ # Current versions of this library support streaming a IO or IO-like
9
+ # object to using MogileFS::MogileFS#store_file, so using StoreContent
10
+ # may no longer be necessary.
94
11
  class StoreContent < Proc
95
12
  def initialize(total_size, &writer_proc)
96
13
  @total_size = total_size
@@ -100,7 +17,6 @@ module MogileFS::Util
100
17
  @total_size
101
18
  end
102
19
  end
103
-
104
20
  end
105
21
 
106
22
  require 'timeout'
@@ -109,82 +25,3 @@ require 'timeout'
109
25
  # reason we require the 'timeout' module, otherwise that module is
110
26
  # broken and worthless to us.
111
27
  class MogileFS::Timeout < Timeout::Error; end
112
-
113
- class Socket
114
- attr_accessor :mogilefs_addr, :mogilefs_connected, :mogilefs_size
115
-
116
- # Socket lacks peeraddr method of the IPSocket/TCPSocket classes
117
- def mogilefs_peername
118
- Socket.unpack_sockaddr_in(getpeername).reverse.map {|x| x.to_s }.join(':')
119
- end
120
-
121
- def mogilefs_init(host = nil, port = nil)
122
- return true if defined?(@mogilefs_connected)
123
-
124
- @mogilefs_addr = Socket.sockaddr_in(port, host).freeze if port && host
125
-
126
- begin
127
- connect_nonblock(@mogilefs_addr)
128
- @mogilefs_connected = true
129
- rescue Errno::EINPROGRESS
130
- nil
131
- rescue Errno::EISCONN
132
- @mogilefs_connected = true
133
- end
134
- end
135
-
136
- class << self
137
-
138
- # Creates a new (TCP) Socket and initiates (but does not wait for) the
139
- # connection
140
- def mogilefs_new_nonblock(host, port)
141
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
142
- if defined?(Socket::TCP_NODELAY)
143
- sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
144
- end
145
- sock.mogilefs_init(host, port)
146
- sock
147
- end
148
-
149
- # Like TCPSocket.new(host, port), but with an explicit timeout
150
- # (and we don't care for local address/port we're binding to).
151
- # This raises MogileFS::Timeout if timeout expires
152
- def mogilefs_new(host, port, timeout = 5.0)
153
- sock = mogilefs_new_nonblock(host, port) or return sock
154
-
155
- while timeout > 0
156
- t0 = Time.now
157
- r = IO.select(nil, [sock], nil, timeout)
158
- return sock if r && r[1] && sock.mogilefs_init
159
- timeout -= (Time.now - t0)
160
- end
161
-
162
- sock.close rescue nil
163
- raise MogileFS::Timeout, 'socket write timeout'
164
- end
165
-
166
- include MogileFS::Util
167
-
168
- # Makes a request on a new TCP Socket and returns with a readble socket
169
- # within the given timeout.
170
- # This raises MogileFS::Timeout if timeout expires
171
- def mogilefs_new_request(host, port, request, timeout = 5.0)
172
- t0 = Time.now
173
- sock = mogilefs_new(host, port, timeout)
174
- syswrite_full(sock, request, timeout)
175
- timeout -= (Time.now - t0)
176
- if timeout < 0
177
- sock.close rescue nil
178
- raise MogileFS::Timeout, 'socket read timeout'
179
- end
180
- r = IO.select([sock], nil, nil, timeout)
181
- return sock if r && r[0]
182
-
183
- sock.close rescue nil
184
- raise MogileFS::Timeout, 'socket read timeout'
185
- end
186
-
187
- end
188
-
189
- end
190
-
data/test/aggregate.rb CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/ruby -n
1
+ #!/usr/bin/ruby
2
2
  # -*- encoding: binary -*-
3
- BEGIN { $tests = $assertions = $failures = $errors = 0 }
3
+ $tests = $assertions = $failures = $errors = 0
4
4
 
5
- $_ =~ /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/ or next
6
- $tests += $1.to_i
7
- $assertions += $2.to_i
8
- $failures += $3.to_i
9
- $errors += $4.to_i
5
+ STDIN.each_line do |l|
6
+ l =~ /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/ or next
7
+ $tests += $1.to_i
8
+ $assertions += $2.to_i
9
+ $failures += $3.to_i
10
+ $errors += $4.to_i
11
+ end
10
12
 
11
- END {
12
- printf("\n%d tests, %d assertions, %d failures, %d errors\n",
13
- $tests, $assertions, $failures, $errors)
14
- }
13
+ printf("\n%d tests, %d assertions, %d failures, %d errors\n",
14
+ $tests, $assertions, $failures, $errors)