mogilefs-client 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,15 +12,15 @@ clean:
12
12
 
13
13
 
14
14
  ifndef V
15
- quiet_pre = @echo '* $@';
16
- quiet_post = >$(t) 2>&1
15
+ quiet_pre = @echo '* $@';
16
+ quiet_post = >$(t) 2>&1
17
17
  else
18
- # we can't rely on -o pipefail outside of bash 3+,
19
- # so we use a stamp file to indicate success and
20
- # have rm fail if the stamp didn't get created
21
- stamp = $@$(log_suffix).ok
22
- quiet_pre = @echo $(ruby) $@ $(TEST_OPTS); ! test -f $(stamp) && (
23
- quiet_post = && > $(stamp) )>&2 | tee $(t); rm $(stamp) 2>/dev/null
18
+ # we can't rely on -o pipefail outside of bash 3+,
19
+ # so we use a stamp file to indicate success and
20
+ # have rm fail if the stamp didn't get created
21
+ stamp = $@$(log_suffix).ok
22
+ quiet_pre = @echo $(ruby) $@ $(TEST_OPTS); ! test -f $(stamp) && (
23
+ quiet_post = && > $(stamp) )>&2 | tee $(t); rm $(stamp) 2>/dev/null
24
24
  endif
25
25
  ruby = ruby
26
26
  run_test = $(quiet_pre) setsid $(ruby) -w $@ $(TEST_OPTS) $(quiet_post) || \
@@ -1,3 +1,7 @@
1
+ = 2.2.0
2
+ * internal cleanups (no public API breakage)
3
+ * refactor backend socket/connection handling for reliability
4
+
1
5
  = 2.1.0
2
6
  * MySQL interface returns integer length and devcount (API change)
3
7
  * Ensure store_{content,file} always returns size (API fix)
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  ##
2
3
  # MogileFS is a Ruby client for Danga Interactive's open source distributed
3
4
  # filesystem.
@@ -6,7 +7,7 @@
6
7
 
7
8
  module MogileFS
8
9
 
9
- VERSION = '2.1.0'.freeze
10
+ VERSION = '2.2.0'
10
11
 
11
12
  ##
12
13
  # Raised when a socket remains unreadable for too long.
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs/client'
2
3
 
3
4
  ##
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs'
2
3
  require 'mogilefs/util'
3
4
  require 'thread'
@@ -74,10 +75,7 @@ class MogileFS::Backend
74
75
  # Closes this backend's socket.
75
76
 
76
77
  def shutdown
77
- if @socket
78
- @socket.close rescue nil # ignore errors
79
- @socket = nil
80
- end
78
+ @mutex.synchronize { shutdown_unlocked }
81
79
  end
82
80
 
83
81
  # MogileFS::MogileFS commands
@@ -147,29 +145,44 @@ class MogileFS::Backend
147
145
 
148
146
  private unless defined? $TESTING
149
147
 
148
+ # record-separator for mogilefsd responses, update this if the protocol
149
+ # changes
150
+ RS = "\n"
151
+
152
+ def shutdown_unlocked # :nodoc:
153
+ if @socket
154
+ @socket.close rescue nil # ignore errors
155
+ @socket = nil
156
+ end
157
+ end
158
+
150
159
  ##
151
160
  # Performs the +cmd+ request with +args+.
152
161
 
153
162
  def do_request(cmd, args)
163
+ response = nil
164
+ request = make_request cmd, args
154
165
  @mutex.synchronize do
155
- request = make_request cmd, args
156
-
157
166
  begin
158
- bytes_sent = socket.send request, 0
159
- rescue SystemCallError
160
- shutdown
161
- raise MogileFS::UnreachableBackendError
162
- end
163
-
164
- unless bytes_sent == request.length then
165
- raise MogileFS::RequestTruncatedError,
166
- "request truncated (sent #{bytes_sent} expected #{request.length})"
167
+ io = socket
168
+ begin
169
+ bytes_sent = io.write request
170
+ bytes_sent == request.size or
171
+ raise MogileFS::RequestTruncatedError,
172
+ "request truncated (sent #{bytes_sent} expected #{request.size})"
173
+ rescue SystemCallError
174
+ raise MogileFS::UnreachableBackendError
175
+ end
176
+
177
+ readable?(io)
178
+ response = io.gets(RS) and return parse_response(response)
179
+ ensure
180
+ # we DO NOT want the response we timed out waiting for, to crop up later
181
+ # on, on the same socket, intersperesed with a subsequent request!
182
+ # we close the socket if it times out like this
183
+ response or shutdown_unlocked
167
184
  end
168
-
169
- readable?
170
-
171
- parse_response(socket.gets)
172
- end
185
+ end # @mutex.synchronize
173
186
  end
174
187
 
175
188
  ##
@@ -192,11 +205,10 @@ class MogileFS::Backend
192
205
  # error, or raises, as appropriate.
193
206
 
194
207
  def parse_response(line)
195
- if line =~ /^ERR\s+(\w+)\s*(.*)/ then
208
+ if line =~ /^ERR\s+(\w+)\s*([^\r\n]*)/
196
209
  @lasterr = $1
197
210
  @lasterrstr = $2 ? url_unescape($2) : nil
198
211
  raise error(@lasterr), @lasterrstr
199
- return nil
200
212
  end
201
213
 
202
214
  return url_decode($1) if line =~ /^OK\s+\d*\s*(\S*)/
@@ -208,26 +220,18 @@ class MogileFS::Backend
208
220
  ##
209
221
  # Raises if the socket does not become readable in +@timeout+ seconds.
210
222
 
211
- def readable?
223
+ def readable?(io = @socket)
212
224
  timeleft = @timeout
213
225
  peer = nil
214
226
  loop do
215
227
  t0 = Time.now
216
- found = IO.select([socket], nil, nil, timeleft)
228
+ found = IO.select([io], nil, nil, timeleft)
217
229
  return true if found && found[0]
218
230
  timeleft -= (Time.now - t0)
231
+ timeleft >= 0 and next
232
+ peer = io ? "#{io.mogilefs_peername} " : nil
219
233
 
220
- if timeleft < 0
221
- peer = @socket ? "#{@socket.mogilefs_peername} " : nil
222
-
223
- # we DO NOT want the response we timed out waiting for, to crop up later
224
- # on, on the same socket, intersperesed with a subsequent request! so,
225
- # we close the socket if it times out like this
226
- shutdown
227
- raise MogileFS::UnreadableSocketError, "#{peer}never became readable"
228
- break
229
- end
230
- shutdown
234
+ raise MogileFS::UnreadableSocketError, "#{peer}never became readable"
231
235
  end
232
236
  false
233
237
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'zlib'
2
3
  require 'digest/md5'
3
4
  require 'uri'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs/backend'
2
3
 
3
4
  ##
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'stringio'
2
3
  require 'uri'
3
4
  require 'mogilefs/backend'
@@ -89,7 +90,6 @@ class MogileFS::HTTPFile < StringIO
89
90
  def upload(devid, uri)
90
91
  file_size = length
91
92
  sock = Socket.mogilefs_new(uri.host, uri.port)
92
- sock.mogilefs_tcp_cork = true
93
93
 
94
94
  if @streaming_io
95
95
  file_size = @streaming_io.length
@@ -102,7 +102,6 @@ class MogileFS::HTTPFile < StringIO
102
102
  # Don't try to run out of memory
103
103
  File.open(@big_io, "rb") do |fp|
104
104
  file_size = fp.stat.size
105
- fp.sync = true
106
105
  syswrite_full(sock, "PUT #{uri.request_uri} HTTP/1.0\r\n" \
107
106
  "Content-Length: #{file_size}\r\n\r\n")
108
107
  sysrwloop(fp, sock)
@@ -111,7 +110,6 @@ class MogileFS::HTTPFile < StringIO
111
110
  syswrite_full(sock, "PUT #{uri.request_uri} HTTP/1.0\r\n" \
112
111
  "Content-Length: #{length}\r\n\r\n#{string}")
113
112
  end
114
- sock.mogilefs_tcp_cork = false
115
113
 
116
114
  line = sock.gets or
117
115
  raise EmptyResponseError, 'Unable to read response line from server'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs/client'
2
3
  require 'mogilefs/util'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs'
2
3
  require 'mogilefs/backend' # for the exceptions
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs'
2
3
  require 'socket'
3
4
  require 'mogilefs/util'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'thread'
2
3
  require 'mogilefs'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'mogilefs'
2
3
  require 'socket'
3
4
 
@@ -112,15 +113,6 @@ class MogileFS::Timeout < Timeout::Error; end
112
113
  class Socket
113
114
  attr_accessor :mogilefs_addr, :mogilefs_connected, :mogilefs_size
114
115
 
115
- TCP_CORK = 3 if ! defined?(TCP_CORK) && RUBY_PLATFORM =~ /linux/
116
-
117
- def mogilefs_tcp_cork=(set)
118
- if defined?(TCP_CORK)
119
- self.setsockopt(SOL_TCP, TCP_CORK, set ? 1 : 0) rescue nil
120
- end
121
- set
122
- end
123
-
124
116
  # Socket lacks peeraddr method of the IPSocket/TCPSocket classes
125
117
  def mogilefs_peername
126
118
  Socket.unpack_sockaddr_in(getpeername).reverse.map {|x| x.to_s }.join(':')
@@ -147,7 +139,6 @@ class Socket
147
139
  # connection
148
140
  def mogilefs_new_nonblock(host, port)
149
141
  sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
150
- sock.sync = true
151
142
  if defined?(Socket::TCP_NODELAY)
152
143
  sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
153
144
  end
data/setup.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  #
2
3
  # setup.rb
3
4
  #
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/ruby -n
2
+ # -*- encoding: binary -*-
2
3
  BEGIN { $tests = $assertions = $failures = $errors = 0 }
3
4
 
4
5
  $_ =~ /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/ or next
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  STDIN.sync = STDOUT.sync = STDERR.sync = true
2
3
  require 'test/unit'
3
4
  require 'tempfile'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
 
3
4
  class TestMogileFS__Admin < TestMogileFS
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/unit'
2
3
  require 'test/setup'
3
4
 
@@ -57,7 +58,7 @@ class TestBackend < Test::Unit::TestCase
57
58
  socket_request = ''
58
59
  socket = Object.new
59
60
  def socket.closed?() false end
60
- def socket.send(request, flags) raise SystemCallError, 'dummy' end
61
+ def socket.write(request) raise SystemCallError, 'dummy' end
61
62
 
62
63
  @backend.instance_variable_set '@socket', socket
63
64
 
@@ -92,7 +93,7 @@ class TestBackend < Test::Unit::TestCase
92
93
  socket_request = ''
93
94
  socket = Object.new
94
95
  def socket.closed?() false end
95
- def socket.send(request, flags) return request.length - 1 end
96
+ def socket.write(request) return request.length - 1 end
96
97
 
97
98
  @backend.instance_variable_set '@socket', socket
98
99
 
@@ -127,21 +128,16 @@ class TestBackend < Test::Unit::TestCase
127
128
  end
128
129
  end
129
130
 
130
- def test_readable_eh_readable
131
- accept = Tempfile.new('accept')
132
- tmp = TempServer.new(Proc.new do |serv, port|
133
- client, client_addr = serv.accept
134
- client.sync = true
135
- accept.syswrite('.')
136
- client.send('.', 0)
137
- sleep
138
- end)
131
+ def test_parse_response_newline
132
+ begin
133
+ @backend.parse_response("ERR you totally suck\r\n")
134
+ rescue MogileFS::Error => err
135
+ assert_equal 'MogileFS::Backend::YouError', err.class.to_s
136
+ assert_equal 'totally suck', err.message
137
+ end
139
138
 
140
- @backend = MogileFS::Backend.new :hosts => [ "127.0.0.1:#{tmp.port}" ]
141
- assert_equal true, @backend.readable?
142
- assert_equal 1, accept.stat.size
143
- ensure
144
- TempServer.destroy_all!
139
+ assert_equal 'you', @backend.lasterr
140
+ assert_equal 'totally suck', @backend.lasterrstr
145
141
  end
146
142
 
147
143
  def test_readable_eh_not_readable
@@ -149,7 +145,7 @@ class TestBackend < Test::Unit::TestCase
149
145
  @backend = MogileFS::Backend.new(:hosts => [ "127.0.0.1:#{tmp.port}" ],
150
146
  :timeout => 0.5)
151
147
  begin
152
- @backend.readable?
148
+ @backend.do_request 'foo', {}
153
149
  rescue MogileFS::UnreadableSocketError => e
154
150
  assert_equal "127.0.0.1:#{tmp.port} never became readable", e.message
155
151
  rescue Exception => err
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
  require 'mogilefs/bigfile'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/unit'
2
3
  require 'mogilefs'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
  require 'mogilefs/mysql'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
  require 'stringio'
3
4
  require 'tempfile'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
  require 'mogilefs/mysql'
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
  require 'mogilefs'
3
4
  require 'mogilefs/network'
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/unit'
2
3
 
3
4
  $TESTING = true
@@ -1,3 +1,4 @@
1
+ # -*- encoding: binary -*-
1
2
  require 'test/setup'
2
3
 
3
4
  class TestMogileFS__Util < Test::Unit::TestCase
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mogilefs-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ hash: 7
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 2
9
+ - 0
10
+ version: 2.2.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Eric Wong
@@ -10,29 +16,41 @@ autorequire:
10
16
  bindir: bin
11
17
  cert_chain: []
12
18
 
13
- date: 2009-04-11 00:00:00 -07:00
19
+ date: 2011-01-13 00:00:00 +00:00
14
20
  default_executable:
15
21
  dependencies:
16
22
  - !ruby/object:Gem::Dependency
17
23
  name: ZenTest
18
- type: :development
19
- version_requirement:
20
- version_requirements: !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
21
27
  requirements:
22
28
  - - ">="
23
29
  - !ruby/object:Gem::Version
30
+ hash: 29
31
+ segments:
32
+ - 3
33
+ - 6
34
+ - 1
24
35
  version: 3.6.1
25
- version:
36
+ type: :development
37
+ version_requirements: *id001
26
38
  - !ruby/object:Gem::Dependency
27
39
  name: hoe
28
- type: :development
29
- version_requirement:
30
- version_requirements: !ruby/object:Gem::Requirement
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
31
43
  requirements:
32
44
  - - ">="
33
45
  - !ruby/object:Gem::Version
34
- version: 1.10.0
35
- version:
46
+ hash: 47
47
+ segments:
48
+ - 2
49
+ - 8
50
+ - 0
51
+ version: 2.8.0
52
+ type: :development
53
+ version_requirements: *id002
36
54
  description: "Source repository (git):"
37
55
  email: normalperson@yhbt.net
38
56
  executables:
@@ -80,6 +98,8 @@ files:
80
98
  - test/test_util.rb
81
99
  has_rdoc: true
82
100
  homepage: http://seattlerb.rubyforge.org/mogilefs-client
101
+ licenses: []
102
+
83
103
  post_install_message:
84
104
  rdoc_options:
85
105
  - --main
@@ -87,32 +107,38 @@ rdoc_options:
87
107
  require_paths:
88
108
  - lib
89
109
  required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
90
111
  requirements:
91
112
  - - ">="
92
113
  - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
116
+ - 0
93
117
  version: "0"
94
- version:
95
118
  required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
96
120
  requirements:
97
121
  - - ">="
98
122
  - !ruby/object:Gem::Version
123
+ hash: 3
124
+ segments:
125
+ - 0
99
126
  version: "0"
100
- version:
101
127
  requirements: []
102
128
 
103
129
  rubyforge_project: seattlerb
104
- rubygems_version: 1.3.1
130
+ rubygems_version: 1.3.7
105
131
  signing_key:
106
- specification_version: 2
132
+ specification_version: 3
107
133
  summary: A Ruby MogileFS client
108
134
  test_files:
109
- - test/test_bigfile.rb
110
- - test/test_pool.rb
111
135
  - test/test_db_backend.rb
112
- - test/test_mogilefs.rb
113
136
  - test/test_network.rb
114
137
  - test/test_mysql.rb
115
- - test/test_client.rb
116
- - test/test_admin.rb
117
138
  - test/test_util.rb
118
139
  - test/test_backend.rb
140
+ - test/test_mogilefs.rb
141
+ - test/test_client.rb
142
+ - test/test_admin.rb
143
+ - test/test_pool.rb
144
+ - test/test_bigfile.rb