mogilefs-client 2.0.2 → 2.1.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.
- data/GNUmakefile +18 -4
- data/History.txt +9 -0
- data/README.txt +10 -5
- data/bin/mog +1 -2
- data/lib/mogilefs/bigfile.rb +1 -1
- data/lib/mogilefs/mogilefs.rb +48 -63
- data/lib/mogilefs/mysql.rb +14 -5
- data/lib/mogilefs/network.rb +5 -3
- data/lib/mogilefs/util.rb +30 -2
- data/lib/mogilefs.rb +1 -1
- data/test/setup.rb +13 -8
- data/test/test_mogilefs.rb +60 -12
- data/test/test_mysql.rb +34 -2
- data/test/test_util.rb +61 -0
- metadata +4 -4
data/GNUmakefile
CHANGED
@@ -10,12 +10,26 @@ test: $(T)
|
|
10
10
|
clean:
|
11
11
|
$(RM) $(TO) $(addsuffix +,$(TO))
|
12
12
|
|
13
|
-
t = $(basename $(notdir $@))
|
14
|
-
t_log = $(subst .rb,.log,$@)
|
15
13
|
|
14
|
+
ifndef V
|
15
|
+
quiet_pre = @echo '* $@';
|
16
|
+
quiet_post = >$(t) 2>&1
|
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
|
24
|
+
endif
|
25
|
+
ruby = ruby
|
26
|
+
run_test = $(quiet_pre) setsid $(ruby) -w $@ $(TEST_OPTS) $(quiet_post) || \
|
27
|
+
(sed "s,^,$(extra): ," >&2 < $(t); exit 1)
|
28
|
+
|
29
|
+
$(T): t = $(subst .rb,.log,$@)
|
30
|
+
$(T): export RUBYLIB := $(CURDIR)/lib:$(RUBYLIB)
|
16
31
|
$(T):
|
17
|
-
|
18
|
-
@mv $(t_log)+ $(t_log)
|
32
|
+
$(run_test)
|
19
33
|
|
20
34
|
# using make instead of rake since Rakefile takes too long to load
|
21
35
|
manifest: Manifest.txt
|
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
= 2.1.0
|
2
|
+
* MySQL interface returns integer length and devcount (API change)
|
3
|
+
* Ensure store_{content,file} always returns size (API fix)
|
4
|
+
* Add get_uris API method
|
5
|
+
* Respect timeout when doing get_file_data
|
6
|
+
* MySQL interface filters out URLs for down/dead hosts/devices
|
7
|
+
* Really remove all NFS support
|
8
|
+
* get_file in slurp mode slurps all output correctly
|
9
|
+
|
1
10
|
= 2.0.2
|
2
11
|
* README.txt: update documentation URL
|
3
12
|
* backend: raise exceptions with the error message
|
data/README.txt
CHANGED
@@ -14,15 +14,20 @@ File bugs:
|
|
14
14
|
|
15
15
|
http://rubyforge.org/tracker/?func=add&group_id=1513&atid=5921
|
16
16
|
|
17
|
-
|
17
|
+
Please email Eric Wong at normalperson@yhbt.net as well since
|
18
|
+
he finds web interfaces difficult to use.
|
18
19
|
|
19
|
-
git
|
20
|
+
Source repository (git):
|
20
21
|
|
21
|
-
|
22
|
+
git://git.bogomips.org/mogilefs-client.git
|
23
|
+
http://git.bogomips.org/mogilefs-client.git
|
24
|
+
git://repo.or.cz/ruby-mogilefs-client.git (mirror)
|
25
|
+
http://repo.or.cz/r/ruby-mogilefs-client.git (mirror)
|
22
26
|
|
23
|
-
Repository
|
27
|
+
Repository browsers:
|
24
28
|
|
25
|
-
http://git.bogomips.org/cgit/mogilefs-client.git
|
29
|
+
* http://git.bogomips.org/cgit/mogilefs-client.git (cgit)
|
30
|
+
* http://repo.or.cz/w/ruby-mogilefs-client.git (gitweb mirror)
|
26
31
|
|
27
32
|
== About
|
28
33
|
|
data/bin/mog
CHANGED
@@ -186,7 +186,6 @@ begin
|
|
186
186
|
cfg[:class] or raise ArgumentError, 'E: --class must be specified'
|
187
187
|
buf = ''
|
188
188
|
tmp = Tempfile.new('mog-tee') # TODO: explore Transfer-Encoding:chunked :)
|
189
|
-
at_exit { tmp.unlink }
|
190
189
|
|
191
190
|
# if stdout is pointing to /dev/null, don't bother installing the filter.
|
192
191
|
STDOUT.sync = true
|
@@ -196,7 +195,7 @@ begin
|
|
196
195
|
sysrwloop(STDIN, tmp, tee_filter)
|
197
196
|
store_file_retry(mg, key, cfg[:class], tmp.path)
|
198
197
|
ensure
|
199
|
-
tmp.close
|
198
|
+
tmp.close!
|
200
199
|
end
|
201
200
|
when 'test'
|
202
201
|
truth, ok = true, nil
|
data/lib/mogilefs/bigfile.rb
CHANGED
data/lib/mogilefs/mogilefs.rb
CHANGED
@@ -19,10 +19,6 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
19
19
|
|
20
20
|
attr_accessor :get_file_data_timeout
|
21
21
|
|
22
|
-
##
|
23
|
-
# internal Regexp for matching an "HTTP 200 OK" head response
|
24
|
-
HTTP_200_OK = %r{\AHTTP/\d+\.\d+\s+200\s+}.freeze
|
25
|
-
|
26
22
|
##
|
27
23
|
# Creates a new MogileFS::MogileFS instance. +args+ must include a key
|
28
24
|
# :domain specifying the domain of this client.
|
@@ -61,27 +57,20 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
61
57
|
# Retrieves the contents of +key+.
|
62
58
|
|
63
59
|
def get_file_data(key, &block)
|
64
|
-
paths = get_paths
|
65
|
-
|
66
|
-
return nil unless paths
|
67
|
-
|
60
|
+
paths = get_paths(key) or return nil
|
68
61
|
paths.each do |path|
|
69
|
-
|
70
|
-
|
71
|
-
when /^http:\/\// then
|
62
|
+
begin
|
63
|
+
sock = http_read_sock(URI.parse(path))
|
72
64
|
begin
|
73
|
-
sock
|
74
|
-
return
|
75
|
-
|
76
|
-
|
77
|
-
next
|
65
|
+
return yield(sock) if block_given?
|
66
|
+
return sysread_full(sock, sock.mogilefs_size, @get_file_data_timeout)
|
67
|
+
ensure
|
68
|
+
sock.close rescue nil
|
78
69
|
end
|
79
|
-
|
80
|
-
|
81
|
-
return File.read(path)
|
70
|
+
rescue MogileFS::Timeout, MogileFS::InvalidResponseError,
|
71
|
+
Errno::ECONNREFUSED, EOFError, SystemCallError
|
82
72
|
end
|
83
73
|
end
|
84
|
-
|
85
74
|
nil
|
86
75
|
end
|
87
76
|
|
@@ -93,7 +82,14 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
93
82
|
:noverify => noverify ? 1 : 0, :zone => zone }
|
94
83
|
@backend.respond_to?(:_get_paths) and return @backend._get_paths(opts)
|
95
84
|
res = @backend.get_paths(opts)
|
96
|
-
(1..res['paths'].to_i).map { |i| res["path#{i}"] }
|
85
|
+
(1..res['paths'].to_i).map { |i| res["path#{i}"] }.compact
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Get the URIs for +key+.
|
90
|
+
|
91
|
+
def get_uris(key, noverify = true, zone = nil)
|
92
|
+
get_paths(key, noverify, zone).map { |path| URI.parse(path) }
|
97
93
|
end
|
98
94
|
|
99
95
|
##
|
@@ -135,20 +131,22 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
135
131
|
|
136
132
|
##
|
137
133
|
# Copies the contents of +file+ into +key+ in class +klass+. +file+ can be
|
138
|
-
# either a file name or an object that responds to #
|
134
|
+
# either a file name or an object that responds to #sysread.
|
135
|
+
# Returns size of +file+ stored
|
139
136
|
|
140
137
|
def store_file(key, klass, file)
|
141
138
|
raise MogileFS::ReadOnlyError if readonly?
|
142
139
|
|
143
140
|
new_file key, klass do |mfp|
|
144
141
|
if file.respond_to? :sysread then
|
145
|
-
|
142
|
+
sysrwloop(file, mfp)
|
146
143
|
else
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
144
|
+
size = File.size(file)
|
145
|
+
if size > 0x10000 # Bigass file, handle differently
|
146
|
+
mfp.big_io = file
|
147
|
+
size
|
148
|
+
else
|
149
|
+
File.open(file, "rb") { |fp| sysrwloop(fp, mfp) }
|
152
150
|
end
|
153
151
|
end
|
154
152
|
end
|
@@ -207,34 +205,13 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
207
205
|
|
208
206
|
def paths_size(paths)
|
209
207
|
paths.each do |path|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
s = Socket.mogilefs_new_request(url.host, url.port,
|
216
|
-
"HEAD #{url.request_uri} HTTP/1.0\r\n\r\n",
|
217
|
-
@get_file_data_timeout)
|
218
|
-
res = s.recv(4096, 0)
|
219
|
-
if res =~ HTTP_200_OK
|
220
|
-
head, body = res.split(/\r\n\r\n/, 2)
|
221
|
-
if head =~ /^Content-Length:\s*(\d+)/i
|
222
|
-
return $1.to_i
|
223
|
-
end
|
224
|
-
end
|
225
|
-
next
|
226
|
-
rescue MogileFS::Timeout, Errno::ECONNREFUSED,
|
227
|
-
EOFError, SystemCallError
|
228
|
-
next
|
229
|
-
ensure
|
230
|
-
s.close rescue nil
|
231
|
-
end
|
232
|
-
else
|
233
|
-
next unless File.exist? path
|
234
|
-
return File.size(path)
|
208
|
+
begin
|
209
|
+
return http_read_sock(URI.parse(path), "HEAD").mogilefs_size
|
210
|
+
rescue MogileFS::InvalidResponseError, MogileFS::Timeout,
|
211
|
+
Errno::ECONNREFUSED, EOFError, SystemCallError => err
|
212
|
+
next
|
235
213
|
end
|
236
214
|
end
|
237
|
-
|
238
215
|
nil
|
239
216
|
end
|
240
217
|
|
@@ -271,19 +248,27 @@ class MogileFS::MogileFS < MogileFS::Client
|
|
271
248
|
|
272
249
|
# given a URI, this returns a readable socket with ready data from the
|
273
250
|
# body of the response.
|
274
|
-
def
|
251
|
+
def http_read_sock(uri, http_method = "GET")
|
275
252
|
sock = Socket.mogilefs_new_request(uri.host, uri.port,
|
276
|
-
|
277
|
-
|
278
|
-
buf = sock.
|
253
|
+
"#{http_method} #{uri.request_uri} HTTP/1.0\r\n\r\n",
|
254
|
+
@get_file_data_timeout)
|
255
|
+
buf = sock.recv_nonblock(4096, Socket::MSG_PEEK)
|
279
256
|
head, body = buf.split(/\r\n\r\n/, 2)
|
280
|
-
|
281
|
-
|
257
|
+
|
258
|
+
# we're dealing with a seriously slow/stupid HTTP server if we can't
|
259
|
+
# get the header in a single read(2) syscall.
|
260
|
+
if head =~ %r{\AHTTP/\d+\.\d+\s+200\s*} &&
|
261
|
+
head =~ %r{^Content-Length:\s*(\d+)}i
|
262
|
+
sock.mogilefs_size = $1.to_i
|
263
|
+
case http_method
|
264
|
+
when "HEAD" then sock.close
|
265
|
+
when "GET" then sock.recv(head.size + 4, 0)
|
266
|
+
end
|
282
267
|
return sock
|
283
268
|
end
|
269
|
+
sock.close rescue nil
|
284
270
|
raise MogileFS::InvalidResponseError,
|
285
|
-
"
|
286
|
-
end # def
|
271
|
+
"#{http_method} on #{uri} returned: #{head.inspect}"
|
272
|
+
end # def http_read_sock
|
287
273
|
|
288
274
|
end
|
289
|
-
|
data/lib/mogilefs/mysql.rb
CHANGED
@@ -55,7 +55,7 @@ class MogileFS::Mysql
|
|
55
55
|
|
56
56
|
keys = []
|
57
57
|
query(sql).each do |dkey,length,devcount|
|
58
|
-
yield(dkey, length, devcount) if block_given?
|
58
|
+
yield(dkey, length.to_i, devcount.to_i) if block_given?
|
59
59
|
keys << dkey
|
60
60
|
end
|
61
61
|
|
@@ -101,7 +101,7 @@ class MogileFS::Mysql
|
|
101
101
|
devices = refresh_device(true)
|
102
102
|
devinfo = devices[devid.to_i] or next
|
103
103
|
end
|
104
|
-
|
104
|
+
devinfo[:readable] or next
|
105
105
|
port = devinfo[:http_get_port]
|
106
106
|
host = zone && zone == 'alt' ? devinfo[:altip] : devinfo[:hostip]
|
107
107
|
nfid = '%010u' % fid
|
@@ -120,10 +120,10 @@ class MogileFS::Mysql
|
|
120
120
|
GET_DOMAINS = 'SELECT dmid,namespace FROM domain'.freeze
|
121
121
|
|
122
122
|
GET_DEVICES = <<-EOS
|
123
|
-
SELECT d.devid, h.hostip, h.altip, h.http_port, h.http_get_port
|
123
|
+
SELECT d.devid, h.hostip, h.altip, h.http_port, h.http_get_port,
|
124
|
+
d.status, h.status
|
124
125
|
FROM device d
|
125
126
|
LEFT JOIN host h ON d.hostid = h.hostid
|
126
|
-
WHERE d.status IN ('alive','readonly','drain');
|
127
127
|
EOS
|
128
128
|
GET_DEVICES.freeze
|
129
129
|
end
|
@@ -132,15 +132,24 @@ class MogileFS::Mysql
|
|
132
132
|
@my.send(@query_method, sql)
|
133
133
|
end
|
134
134
|
|
135
|
+
DEV_STATUS_READABLE = {
|
136
|
+
"alive" => true,
|
137
|
+
"readonly" => true,
|
138
|
+
"drain" => true,
|
139
|
+
}.freeze
|
140
|
+
|
135
141
|
def refresh_device(force = false)
|
136
142
|
return @cache_device if ! force && ((Time.now - @last_update_device) < 60)
|
137
143
|
tmp = {}
|
138
144
|
res = query(GET_DEVICES)
|
139
|
-
res.each do |devid, hostip, altip, http_port, http_get_port
|
145
|
+
res.each do |devid, hostip, altip, http_port, http_get_port,
|
146
|
+
dev_status, host_status|
|
140
147
|
http_port = http_port ? http_port.to_i : 80
|
141
148
|
tmp[devid.to_i] = {
|
142
149
|
:hostip => hostip.freeze,
|
143
150
|
:altip => (altip || hostip).freeze,
|
151
|
+
:readable => (host_status == "alive" &&
|
152
|
+
DEV_STATUS_READABLE.include?(dev_status)),
|
144
153
|
:http_port => http_port,
|
145
154
|
:http_get_port => http_get_port ? http_get_port.to_i : http_port,
|
146
155
|
}.freeze
|
data/lib/mogilefs/network.rb
CHANGED
@@ -57,9 +57,11 @@ module MogileFS::Network
|
|
57
57
|
|
58
58
|
r[1].each do |sock|
|
59
59
|
begin
|
60
|
-
# we don't about short/interrupted writes here, if the
|
61
|
-
# request fails or blocks then the server is
|
62
|
-
|
60
|
+
# we don't care about short/interrupted writes here, if the
|
61
|
+
# following request fails or blocks then the server is
|
62
|
+
# flat-out hopeless
|
63
|
+
sock.write_nonblock(
|
64
|
+
"HEAD #{uri_socks[sock].request_uri} HTTP/1.0\r\n\r\n")
|
63
65
|
sockets << sock
|
64
66
|
rescue
|
65
67
|
sock.close rescue nil
|
data/lib/mogilefs/util.rb
CHANGED
@@ -67,6 +67,29 @@ module MogileFS::Util
|
|
67
67
|
# should never get here
|
68
68
|
end
|
69
69
|
|
70
|
+
def sysread_full(io_rd, size, timeout = nil, full_timeout = false)
|
71
|
+
tmp = [] # avoid expensive string concatenation with every loop iteration
|
72
|
+
reader = io_rd.method(timeout ? :read_nonblock : :sysread)
|
73
|
+
begin
|
74
|
+
while size > 0
|
75
|
+
tmp << reader.call(size)
|
76
|
+
size -= tmp.last.size
|
77
|
+
end
|
78
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
79
|
+
t0 = Time.now
|
80
|
+
r = IO.select([ io_rd ], nil, nil, timeout)
|
81
|
+
if timeout
|
82
|
+
timeout -= (Time.now - t0) if full_timeout
|
83
|
+
if !(r && r[0]) || timeout < 0
|
84
|
+
raise MogileFS::Timeout, 'sysread_full timeout'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
retry
|
88
|
+
rescue EOFError
|
89
|
+
end
|
90
|
+
tmp.join('')
|
91
|
+
end
|
92
|
+
|
70
93
|
class StoreContent < Proc
|
71
94
|
def initialize(total_size, &writer_proc)
|
72
95
|
@total_size = total_size
|
@@ -87,7 +110,7 @@ require 'timeout'
|
|
87
110
|
class MogileFS::Timeout < Timeout::Error; end
|
88
111
|
|
89
112
|
class Socket
|
90
|
-
attr_accessor :mogilefs_addr, :mogilefs_connected
|
113
|
+
attr_accessor :mogilefs_addr, :mogilefs_connected, :mogilefs_size
|
91
114
|
|
92
115
|
TCP_CORK = 3 if ! defined?(TCP_CORK) && RUBY_PLATFORM =~ /linux/
|
93
116
|
|
@@ -159,9 +182,14 @@ class Socket
|
|
159
182
|
sock = mogilefs_new(host, port, timeout)
|
160
183
|
syswrite_full(sock, request, timeout)
|
161
184
|
timeout -= (Time.now - t0)
|
162
|
-
|
185
|
+
if timeout < 0
|
186
|
+
sock.close rescue nil
|
187
|
+
raise MogileFS::Timeout, 'socket read timeout'
|
188
|
+
end
|
163
189
|
r = IO.select([sock], nil, nil, timeout)
|
164
190
|
return sock if r && r[0]
|
191
|
+
|
192
|
+
sock.close rescue nil
|
165
193
|
raise MogileFS::Timeout, 'socket read timeout'
|
166
194
|
end
|
167
195
|
|
data/lib/mogilefs.rb
CHANGED
data/test/setup.rb
CHANGED
@@ -65,15 +65,18 @@ class TempServer
|
|
65
65
|
def initialize(server_proc, port = nil)
|
66
66
|
@pid = @sock = nil
|
67
67
|
@port = port
|
68
|
-
retries =
|
68
|
+
retries = 10
|
69
69
|
begin
|
70
70
|
@port ||= 1024 + rand(32768 - 1024)
|
71
71
|
@sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
72
72
|
@sock.bind(Socket.pack_sockaddr_in(@port.to_i, '127.0.0.1'))
|
73
73
|
@sock.listen(5)
|
74
|
-
rescue Errno::EADDRINUSE, Errno::EACCES
|
74
|
+
rescue Errno::EADDRINUSE, Errno::EACCES => err
|
75
75
|
@sock.close rescue nil
|
76
|
-
|
76
|
+
@port = nil
|
77
|
+
retry if port.nil? && (retries -= 1) > 0
|
78
|
+
warn "retries failed: #{retries} port=#{port.inspect}"
|
79
|
+
raise err
|
77
80
|
end
|
78
81
|
@pid = fork { server_proc.call(@sock, @port) }
|
79
82
|
@sock.close rescue nil
|
@@ -106,11 +109,13 @@ end
|
|
106
109
|
class FakeMysql
|
107
110
|
attr_reader :expect
|
108
111
|
TBL_DEVICES = [
|
109
|
-
# devid, hostip,
|
110
|
-
[ 1,
|
111
|
-
[ 2,
|
112
|
-
[ 3,
|
113
|
-
[ 4,
|
112
|
+
# devid, hostip, altip, http_port, http_get_port, dev status, host status
|
113
|
+
[ 1, '10.0.0.1', '192.168.0.1', 7500, 7600, 'readonly', 'alive' ],
|
114
|
+
[ 2, '10.0.0.2', '192.168.0.2', 7500, 7600, 'alive', 'alive' ],
|
115
|
+
[ 3, '10.0.0.3', nil, 7500, nil, 'readonly', 'alive' ],
|
116
|
+
[ 4, '10.0.0.4', nil, 7500, nil, 'alive', 'alive' ],
|
117
|
+
[ 5, '10.0.0.5', nil, 7500, nil, 'dead', 'alive' ],
|
118
|
+
[ 6, '10.0.0.6', nil, 7500, nil, 'alive', 'down' ],
|
114
119
|
]
|
115
120
|
TBL_DOMAINS = [
|
116
121
|
# dmid, namespace
|
data/test/test_mogilefs.rb
CHANGED
@@ -54,8 +54,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
54
54
|
readed = client.recv(4096, 0)
|
55
55
|
assert(readed =~ \
|
56
56
|
%r{\AGET /dev1/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
57
|
-
client.send("HTTP/1.0 404 Not Found\r\n\r\ndata!", 0)
|
58
57
|
accept.syswrite('.')
|
58
|
+
client.send("HTTP/1.0 404 Not Found\r\n\r\ndata!", 0)
|
59
59
|
client.close
|
60
60
|
end
|
61
61
|
|
@@ -65,8 +65,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
65
65
|
readed = client.recv(4096, 0)
|
66
66
|
assert(readed =~ \
|
67
67
|
%r{\AGET /dev2/0/000/000/0000000062\.fid HTTP/1.[01]\r\n\r\n\Z})
|
68
|
-
client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
|
69
68
|
accept.syswrite('.')
|
69
|
+
client.send("HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\ndata!", 0)
|
70
70
|
client.close
|
71
71
|
end
|
72
72
|
|
@@ -145,6 +145,18 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
145
145
|
assert_equal expected, @client.get_paths('key').sort
|
146
146
|
end
|
147
147
|
|
148
|
+
def test_get_uris
|
149
|
+
path1 = 'http://rur-1/dev1/0/000/000/0000000062.fid'
|
150
|
+
path2 = 'http://rur-2/dev2/0/000/000/0000000062.fid'
|
151
|
+
|
152
|
+
@backend.get_paths = { 'paths' => 2, 'path1' => path1, 'path2' => path2 }
|
153
|
+
|
154
|
+
expected = [ URI.parse(path1), URI.parse(path2) ]
|
155
|
+
|
156
|
+
assert_equal expected, @client.get_uris('key')
|
157
|
+
end
|
158
|
+
|
159
|
+
|
148
160
|
def test_get_paths_unknown_key
|
149
161
|
@backend.get_paths = ['unknown_key', '']
|
150
162
|
|
@@ -189,7 +201,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
189
201
|
end
|
190
202
|
|
191
203
|
def test_list_keys
|
192
|
-
@backend.list_keys = { 'key_count' => 2, 'next_after' => 'new_key_2',
|
204
|
+
@backend.list_keys = { 'key_count' => '2', 'next_after' => 'new_key_2',
|
193
205
|
'key_1' => 'new_key_1', 'key_2' => 'new_key_2' }
|
194
206
|
|
195
207
|
keys, next_after = @client.list_keys 'new'
|
@@ -198,7 +210,7 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
198
210
|
end
|
199
211
|
|
200
212
|
def test_list_keys_block
|
201
|
-
@backend.list_keys = { 'key_count' => 2, 'next_after' => 'new_key_2',
|
213
|
+
@backend.list_keys = { 'key_count' => '2', 'next_after' => 'new_key_2',
|
202
214
|
'key_1' => 'new_key_1', 'key_2' => 'new_key_2' }
|
203
215
|
http_resp = "HTTP/1.0 200 OK\r\nContent-Length: %u\r\n"
|
204
216
|
srv = Proc.new do |serv, port, size|
|
@@ -212,10 +224,10 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
212
224
|
t1 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) })
|
213
225
|
t2 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 5) })
|
214
226
|
t3 = TempServer.new(Proc.new { |serv, port| srv.call(serv, port, 10) })
|
215
|
-
@backend.get_paths = { 'paths' => 2,
|
227
|
+
@backend.get_paths = { 'paths' => '2',
|
216
228
|
'path1' => "http://127.0.0.1:#{t1.port}/",
|
217
229
|
'path2' => "http://127.0.0.1:#{t2.port}/" }
|
218
|
-
@backend.get_paths = { 'paths' => 1,
|
230
|
+
@backend.get_paths = { 'paths' => '1',
|
219
231
|
'path1' => "http://127.0.0.1:#{t3.port}/" }
|
220
232
|
|
221
233
|
res = []
|
@@ -271,8 +283,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
271
283
|
client.sync = true
|
272
284
|
readed = client.recv(4096, 0) rescue nil
|
273
285
|
assert_equal "HEAD /path HTTP/1.0\r\n\r\n", readed
|
274
|
-
client.send("HTTP/1.0 404 Not Found\r\nContent-Length: 5\r\n\r\n", 0)
|
275
286
|
tmp.syswrite('.')
|
287
|
+
client.send("HTTP/1.0 404 Not Found\r\nContent-Length: 5\r\n\r\n", 0)
|
276
288
|
client.close
|
277
289
|
end)
|
278
290
|
|
@@ -283,6 +295,32 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
283
295
|
assert_equal 1, tmp.stat.size
|
284
296
|
end
|
285
297
|
|
298
|
+
def test_store_file_small_http
|
299
|
+
received = Tempfile.new('received')
|
300
|
+
to_store = Tempfile.new('small')
|
301
|
+
to_store.syswrite('data')
|
302
|
+
|
303
|
+
expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
|
304
|
+
t = TempServer.new(Proc.new do |serv, accept|
|
305
|
+
client, client_addr = serv.accept
|
306
|
+
client.sync = true
|
307
|
+
received.syswrite(client.recv(4096, 0))
|
308
|
+
client.send("HTTP/1.0 200 OK\r\n\r\n", 0)
|
309
|
+
client.close
|
310
|
+
end)
|
311
|
+
|
312
|
+
@backend.create_open = {
|
313
|
+
'devid' => '1',
|
314
|
+
'path' => "http://127.0.0.1:#{t.port}/path",
|
315
|
+
}
|
316
|
+
nr = @client.store_file 'new_key', 'test', to_store.path
|
317
|
+
assert_equal 4, nr
|
318
|
+
received.sysseek(0)
|
319
|
+
assert_equal expected, received.sysread(4096)
|
320
|
+
ensure
|
321
|
+
TempServer.destroy_all!
|
322
|
+
end
|
323
|
+
|
286
324
|
def test_store_content_http
|
287
325
|
received = Tempfile.new('recieved')
|
288
326
|
expected = "PUT /path HTTP/1.0\r\nContent-Length: 4\r\n\r\ndata"
|
@@ -300,7 +338,9 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
300
338
|
'path' => "http://127.0.0.1:#{t.port}/path",
|
301
339
|
}
|
302
340
|
|
303
|
-
@client.store_content 'new_key', 'test', 'data'
|
341
|
+
nr = @client.store_content 'new_key', 'test', 'data'
|
342
|
+
assert nr
|
343
|
+
assert_equal 4, nr
|
304
344
|
|
305
345
|
received.sysseek(0)
|
306
346
|
assert_equal expected, received.sysread(4096)
|
@@ -340,7 +380,9 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
340
380
|
write_callback.call("data")
|
341
381
|
end
|
342
382
|
end
|
343
|
-
|
383
|
+
assert_equal 40, cbk.length
|
384
|
+
nr = @client.store_content('new_key', 'test', cbk)
|
385
|
+
assert_equal 40, nr
|
344
386
|
|
345
387
|
received.sysseek(0)
|
346
388
|
assert_equal expected, received.sysread(4096)
|
@@ -377,7 +419,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
377
419
|
'path_2' => "http://127.0.0.1:#{t2.port}/path",
|
378
420
|
}
|
379
421
|
|
380
|
-
@client.store_content 'new_key', 'test', 'data'
|
422
|
+
nr = @client.store_content 'new_key', 'test', 'data'
|
423
|
+
assert_equal 4, nr
|
381
424
|
received1.sysseek(0)
|
382
425
|
received2.sysseek(0)
|
383
426
|
assert_equal expected, received1.sysread(4096)
|
@@ -421,7 +464,8 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
421
464
|
'path' => "http://127.0.0.1:#{t.port}/path",
|
422
465
|
}
|
423
466
|
|
424
|
-
@client.store_content 'new_key', 'test', ''
|
467
|
+
nr = @client.store_content 'new_key', 'test', ''
|
468
|
+
assert_equal 0, nr
|
425
469
|
received.sysseek(0)
|
426
470
|
assert_equal expected, received.sysread(4096)
|
427
471
|
end
|
@@ -478,7 +522,11 @@ class TestMogileFS__MogileFS < TestMogileFS
|
|
478
522
|
'path' => "http://127.0.0.1:#{t.port}/path",
|
479
523
|
}
|
480
524
|
|
481
|
-
|
525
|
+
orig_size = to_put.size
|
526
|
+
nr = @client.store_file('new_key', 'test', to_put.path)
|
527
|
+
assert nr
|
528
|
+
assert_equal orig_size, nr
|
529
|
+
assert_equal orig_size, to_put.size
|
482
530
|
readed.sysseek(0)
|
483
531
|
assert_equal expect.stat.size, readed.sysread(4096).to_i
|
484
532
|
|
data/test/test_mysql.rb
CHANGED
@@ -20,22 +20,38 @@ class TestMogileFS__Mysql < Test::Unit::TestCase
|
|
20
20
|
{:hostip=>"10.0.0.1",
|
21
21
|
:http_get_port=>7600,
|
22
22
|
:http_port=>7500,
|
23
|
+
:readable=>true,
|
23
24
|
:altip=>"192.168.0.1"},
|
24
25
|
2=>
|
25
26
|
{:hostip=>"10.0.0.2",
|
26
27
|
:http_get_port=>7600,
|
27
28
|
:http_port=>7500,
|
29
|
+
:readable=>true,
|
28
30
|
:altip=>"192.168.0.2"},
|
29
31
|
3=>
|
30
32
|
{:hostip=>"10.0.0.3",
|
31
33
|
:http_get_port=>7500,
|
32
34
|
:http_port=>7500,
|
35
|
+
:readable=>true,
|
33
36
|
:altip=>"10.0.0.3"},
|
34
37
|
4=>
|
35
38
|
{:hostip=>"10.0.0.4",
|
36
39
|
:http_get_port=>7500,
|
37
40
|
:http_port=>7500,
|
38
|
-
:
|
41
|
+
:readable=>true,
|
42
|
+
:altip=>"10.0.0.4"},
|
43
|
+
5=>
|
44
|
+
{:hostip=>"10.0.0.5",
|
45
|
+
:http_get_port=>7500,
|
46
|
+
:http_port=>7500,
|
47
|
+
:readable=>false,
|
48
|
+
:altip=>"10.0.0.5"},
|
49
|
+
6=>
|
50
|
+
{:hostip=>"10.0.0.6",
|
51
|
+
:http_get_port=>7500,
|
52
|
+
:http_port=>7500,
|
53
|
+
:readable=>false,
|
54
|
+
:altip=>"10.0.0.6"}
|
39
55
|
}
|
40
56
|
assert_equal expect, @mg.refresh_device
|
41
57
|
end
|
@@ -53,6 +69,20 @@ class TestMogileFS__Mysql < Test::Unit::TestCase
|
|
53
69
|
assert_equal expect, @mg._get_paths(:domain => 'test', :key => 'fookey')
|
54
70
|
end
|
55
71
|
|
72
|
+
def test_get_paths_bad_device
|
73
|
+
@my.expect << [ [ 12 ] ] # fid
|
74
|
+
@my.expect << [ [ 1 ], [ 6 ] ] # devids
|
75
|
+
expect = [ "http://10.0.0.1:7600/dev1/0/000/000/0000000012.fid" ]
|
76
|
+
assert_equal expect, @mg._get_paths(:domain => 'test', :key => 'fookey')
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_get_paths_bad_host
|
80
|
+
@my.expect << [ [ 12 ] ] # fid
|
81
|
+
@my.expect << [ [ 1 ], [ 5 ] ] # devids
|
82
|
+
expect = [ "http://10.0.0.1:7600/dev1/0/000/000/0000000012.fid" ]
|
83
|
+
assert_equal expect, @mg._get_paths(:domain => 'test', :key => 'fookey')
|
84
|
+
end
|
85
|
+
|
56
86
|
def test_get_paths_alt
|
57
87
|
@my.expect << [ [ 12 ] ] # fid
|
58
88
|
@my.expect << [ [ 1 ], [ 3 ] ] # devids
|
@@ -64,8 +94,10 @@ class TestMogileFS__Mysql < Test::Unit::TestCase
|
|
64
94
|
|
65
95
|
def test_list_keys
|
66
96
|
expect_full = [ [ 'foo', 123, 2 ], [ 'bar', 456, 1 ] ]
|
97
|
+
result_full = eval(expect_full.inspect)
|
98
|
+
result_full.each { |x| (1..2).each { |i| x[i] = x[i].to_s } }
|
67
99
|
expect_keys = [ [ 'foo', 'bar' ], 'bar' ]
|
68
|
-
@my.expect <<
|
100
|
+
@my.expect << result_full
|
69
101
|
full = []
|
70
102
|
keys = @mg._list_keys('test') do |dkey,length,devcount|
|
71
103
|
full << [ dkey, length, devcount ]
|
data/test/test_util.rb
CHANGED
@@ -56,4 +56,65 @@ class TestMogileFS__Util < Test::Unit::TestCase
|
|
56
56
|
t.destroy!
|
57
57
|
end
|
58
58
|
|
59
|
+
def test_sysread_slowly
|
60
|
+
nr = 10
|
61
|
+
str = 'abcde'
|
62
|
+
expect = str * nr
|
63
|
+
rd, wr = IO.pipe
|
64
|
+
pid = fork do
|
65
|
+
rd.close
|
66
|
+
nr.times do
|
67
|
+
syswrite_full(wr, str)
|
68
|
+
sleep(0.1)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
wr.close
|
72
|
+
buf = sysread_full(rd, expect.size)
|
73
|
+
assert_equal expect, buf
|
74
|
+
rd.close
|
75
|
+
ensure
|
76
|
+
Process.kill('TERM', pid) rescue nil
|
77
|
+
Process.waitpid(pid) rescue nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_sysread_timeout
|
81
|
+
nr = 10
|
82
|
+
str = 'abcde'
|
83
|
+
expect = str * nr
|
84
|
+
rd, wr = IO.pipe
|
85
|
+
pid = fork do
|
86
|
+
rd.close
|
87
|
+
nr.times do
|
88
|
+
syswrite_full(wr, str)
|
89
|
+
sleep 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
wr.close
|
93
|
+
assert_raises(MogileFS::Timeout) { sysread_full(rd, expect.size, 0.1) }
|
94
|
+
rd.close
|
95
|
+
ensure
|
96
|
+
Process.kill('TERM', pid) rescue nil
|
97
|
+
Process.waitpid(pid) rescue nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_sysread_full_timeout
|
101
|
+
nr = 100
|
102
|
+
str = 'abcde'
|
103
|
+
expect = str * nr
|
104
|
+
rd, wr = IO.pipe
|
105
|
+
pid = fork do
|
106
|
+
rd.close
|
107
|
+
nr.times do
|
108
|
+
syswrite_full(wr, str)
|
109
|
+
sleep 0.01
|
110
|
+
end
|
111
|
+
end
|
112
|
+
wr.close
|
113
|
+
assert_raises(MogileFS::Timeout) { sysread_full(rd,expect.size,0.1,true) }
|
114
|
+
rd.close
|
115
|
+
ensure
|
116
|
+
Process.kill('TERM', pid) rescue nil
|
117
|
+
Process.waitpid(pid) rescue nil
|
118
|
+
end
|
119
|
+
|
59
120
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mogilefs-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wong
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-04-11 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -31,9 +31,9 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.
|
34
|
+
version: 1.10.0
|
35
35
|
version:
|
36
|
-
description: git
|
36
|
+
description: "Source repository (git):"
|
37
37
|
email: normalperson@yhbt.net
|
38
38
|
executables:
|
39
39
|
- mog
|