mogilefs-client 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|