mogilefs-client 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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