mogilefs-client 3.7.1 → 3.8.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.
- checksums.yaml +7 -0
- data/.document +0 -1
- data/.gitignore +3 -3
- data/{.wrongdoc.yml → .olddoc.yml} +2 -0
- data/GIT-VERSION-GEN +13 -2
- data/GNUmakefile +12 -86
- data/README +19 -9
- data/TODO +0 -4
- data/examples/mog-sync.rb +245 -0
- data/examples/usage_fetcher.rb +44 -0
- data/lib/mogilefs/admin.rb +12 -10
- data/mogilefs-client.gemspec +20 -0
- data/pkg.mk +150 -0
- data/test/fresh.rb +10 -82
- data/test/setup.rb +2 -6
- data/test/test_admin.rb +25 -1
- data/test/test_fresh.rb +71 -0
- data/test/test_mogilefs.rb +25 -29
- data/test/test_mogilefs_integration.rb +15 -5
- data/test/test_mogilefs_integration_large_pipe.rb +7 -3
- data/test/test_mogilefs_integration_list_keys.rb +8 -4
- data/test/test_mogtool_bigfile.rb +7 -3
- metadata +39 -76
- data/.gemtest +0 -0
- data/Rakefile +0 -56
- data/test/integration.rb +0 -43
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 65d3ada1142a27870a3926eeae7d15a13d28b016
|
4
|
+
data.tar.gz: 7ef65f2858cb0a130cbb7c0200946a7df05bf701
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: edecf8b75e5f3e218e63383c79da8ceaab6daed1890c3d51c0ca418936c30e6a613eb187ae5258137570eee8d649a612fcbaaf0cc606baa4165a817f146a681f
|
7
|
+
data.tar.gz: b9448f892913e8104c611badaf368e22acaa6faf60c70abf729200a6c0725efe2657a13498aeeb64b11b4701a62caa7f1f547eefff4c0652834745380dd04e8e
|
data/.document
CHANGED
data/.gitignore
CHANGED
data/GIT-VERSION-GEN
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
CONSTANT = "MogileFS::VERSION"
|
3
3
|
RVF = "lib/mogilefs/version.rb"
|
4
|
-
|
4
|
+
GVF = "GIT-VERSION-FILE"
|
5
|
+
DEF_VER = "v3.8.0"
|
5
6
|
vn = DEF_VER
|
6
7
|
|
7
8
|
# First see if there is a version file (included in release tarballs),
|
@@ -20,9 +21,19 @@ if File.exist?(".git")
|
|
20
21
|
end
|
21
22
|
|
22
23
|
vn = vn.sub!(/\Av/, "")
|
23
|
-
new_ruby_version = "#{CONSTANT} = '#{vn}'
|
24
|
+
new_ruby_version = "#{CONSTANT} = '#{vn}' # :nodoc:\n"
|
24
25
|
cur_ruby_version = File.read(RVF) rescue nil
|
25
26
|
if new_ruby_version != cur_ruby_version
|
26
27
|
File.open(RVF, "w") { |fp| fp.write(new_ruby_version) }
|
27
28
|
end
|
29
|
+
File.chmod(0644, RVF)
|
30
|
+
|
31
|
+
# generate the makefile snippet
|
32
|
+
new_make_version = "GIT_VERSION = #{vn}\n"
|
33
|
+
cur_make_version = File.read(GVF) rescue nil
|
34
|
+
if new_make_version != cur_make_version
|
35
|
+
File.open(GVF, "w") { |fp| fp.write(new_make_version) }
|
36
|
+
end
|
37
|
+
File.chmod(0644, GVF)
|
38
|
+
|
28
39
|
puts vn if $0 == __FILE__
|
data/GNUmakefile
CHANGED
@@ -1,90 +1,16 @@
|
|
1
|
-
|
2
|
-
all:: test
|
1
|
+
all::
|
3
2
|
RSYNC_DEST := bogomips.org:/srv/bogomips/mogilefs-client
|
4
|
-
|
3
|
+
rfpackage := mogilefs-client
|
4
|
+
pkg_extra += lib/mogilefs/version.rb
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
ex := $(shell git ls-files examples/)
|
7
|
+
doc_ex := $(addprefix doc/, $(ex))
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
$(RM) $(TO) $(addsuffix +,$(TO))
|
9
|
+
$(doc_ex): $(ex)
|
10
|
+
mkdir -p $(@D)
|
11
|
+
install -m 644 $< $@
|
12
|
+
-touch -r $< $@ # GNU
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
quiet_post = >$(t) 2>&1
|
19
|
-
else
|
20
|
-
# we can't rely on -o pipefail outside of bash 3+,
|
21
|
-
# so we use a stamp file to indicate success and
|
22
|
-
# have rm fail if the stamp didn't get created
|
23
|
-
stamp = $@$(log_suffix).ok
|
24
|
-
quiet_pre = @echo $(ruby) $@ $(TEST_OPTS); ! test -f $(stamp) && (
|
25
|
-
quiet_post = && > $(stamp) )>&2 | tee $(t); rm $(stamp) 2>/dev/null
|
26
|
-
endif
|
27
|
-
ruby = ruby
|
28
|
-
run_test = $(quiet_pre) setsid $(ruby) -w $@ $(TEST_OPTS) $(quiet_post) || \
|
29
|
-
(sed "s,^,$(extra): ," >&2 < $(t); exit 1)
|
30
|
-
|
31
|
-
$(T): t = $(subst .rb,.log,$@)
|
32
|
-
$(T): export RUBYLIB := $(CURDIR)/lib:$(RUBYLIB)
|
33
|
-
$(T):
|
34
|
-
$(run_test)
|
35
|
-
|
36
|
-
RUBY_VERSION_FILE = lib/mogilefs/version.rb
|
37
|
-
package:
|
38
|
-
git diff --exit-code HEAD^0
|
39
|
-
$(RM) -r pkg/
|
40
|
-
rake fix_perms
|
41
|
-
rake package
|
42
|
-
|
43
|
-
libs := $(wildcard lib/*.rb lib/*/*.rb)
|
44
|
-
flay_flags =
|
45
|
-
flog_flags =
|
46
|
-
flay: $(libs)
|
47
|
-
flay $(flay_flags) $^
|
48
|
-
flog: $(libs)
|
49
|
-
flog $(flog_flags) $^
|
50
|
-
.PHONY: $(T)
|
51
|
-
|
52
|
-
check-warnings:
|
53
|
-
@(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
|
54
|
-
do ruby -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
|
55
|
-
RSYNC = rsync
|
56
|
-
WRONGDOC = wrongdoc
|
57
|
-
|
58
|
-
doc:: .document .wrongdoc.yml $(pkg_extra)
|
59
|
-
-find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
60
|
-
$(RM) -r doc
|
61
|
-
$(WRONGDOC) all
|
62
|
-
install -m644 $(shell LC_ALL=C grep '^[A-Z]' .document) doc/
|
63
|
-
cd doc && \
|
64
|
-
ln -s README README.txt && \
|
65
|
-
ln -s README.html README_txt.html && \
|
66
|
-
ln -s LICENSE LICENSE.txt && \
|
67
|
-
ln -s LICENSE.html LICENSE_txt.html && \
|
68
|
-
ln -s History History.txt && \
|
69
|
-
ln -s History.html History_txt.html
|
70
|
-
|
71
|
-
# Create gzip variants of the same timestamp as the original so nginx
|
72
|
-
# "gzip_static on" can serve the gzipped versions directly.
|
73
|
-
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
74
|
-
doc_gz:
|
75
|
-
for i in $(docs); do \
|
76
|
-
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
77
|
-
|
78
|
-
# this requires GNU coreutils variants
|
79
|
-
ifneq ($(RSYNC_DEST),)
|
80
|
-
publish_doc:
|
81
|
-
-git set-file-times
|
82
|
-
$(MAKE) doc
|
83
|
-
find doc/images -type f | \
|
84
|
-
TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
|
85
|
-
$(MAKE) doc_gz
|
86
|
-
$(RSYNC) -av doc/ $(RSYNC_DEST)/
|
87
|
-
git ls-files | xargs touch
|
88
|
-
endif
|
89
|
-
|
90
|
-
.PHONY: doc .FORCE-GIT-VERSION-FILE
|
14
|
+
include pkg.mk
|
15
|
+
doc::
|
16
|
+
$(MAKE) $(doc_ex)
|
data/README
CHANGED
@@ -9,8 +9,10 @@ MogileFS instance.
|
|
9
9
|
|
10
10
|
rdoc :: http://bogomips.org/mogilefs-client
|
11
11
|
mogilefs :: http://mogilefs.org/
|
12
|
-
list :: mailto:
|
13
|
-
|
12
|
+
list :: mailto:mogilefs-client-public@bogomips.org
|
13
|
+
list-cc :: mailto:mogile@googlegroups.com
|
14
|
+
list-archive :: http://bogomips.org/mogilefs-client-public
|
15
|
+
email :: mailto:e@80x24.org
|
14
16
|
repo :: git://bogomips.org/mogilefs-client.git
|
15
17
|
cgit :: http://bogomips.org/mogilefs-client.git
|
16
18
|
gitweb :: http://repo.or.cz/w/ruby-mogilefs-client.git
|
@@ -35,15 +37,23 @@ See MogileFS::MogileFS
|
|
35
37
|
== Contact
|
36
38
|
|
37
39
|
Feedback (bug reports, user/development discussion, patches, pull
|
38
|
-
requests) are greatly appreciated and handled via email
|
39
|
-
|
40
|
-
|
40
|
+
requests) are greatly appreciated and handled via email to a public
|
41
|
+
inbox. HTML email is considered spam and discarded. No subscription
|
42
|
+
is required or available to post:
|
41
43
|
|
42
|
-
|
43
|
-
mailing list, or if you wish to keep your issue secret, feel free to
|
44
|
-
email Eric Wong at mailto:normalperson@yhbt.net.
|
44
|
+
mogilefs-client-public@bogomips.org
|
45
45
|
|
46
|
-
|
46
|
+
List archives: http://bogomips.org/mogilefs-client-public/
|
47
|
+
|
48
|
+
We may also piggy-back onto the public MogileFS mailing list at
|
49
|
+
mogile@googlegroups.com for feedback (subscription required,
|
50
|
+
unfortunately)
|
51
|
+
|
52
|
+
If you wish to keep your issue secret, feel free to email the author at:
|
53
|
+
|
54
|
+
e@80x24.org
|
55
|
+
|
56
|
+
Do not expect us to read HTML mail under any circumstances.
|
47
57
|
|
48
58
|
== WARNING!
|
49
59
|
|
data/TODO
CHANGED
@@ -0,0 +1,245 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
usage = <<EOF
|
3
|
+
Usage: #$0 SRC_TRACKER_LIST/SRC_DOMAIN DST_TRACKER_LIST/DST_DOMAIN"
|
4
|
+
EOF
|
5
|
+
Thread.abort_on_exception = $stdout.sync = $stderr.sync = true
|
6
|
+
require 'uri'
|
7
|
+
require 'optparse'
|
8
|
+
require 'mogilefs'
|
9
|
+
require 'thread'
|
10
|
+
@verbose = 0
|
11
|
+
copy_jobs = 1
|
12
|
+
jobs = 1
|
13
|
+
keep = nil
|
14
|
+
@dryrun = false
|
15
|
+
opts = {}
|
16
|
+
prefix = ""
|
17
|
+
src_class = dst_class = nil
|
18
|
+
src_maxlen = nil
|
19
|
+
exit_ok = true
|
20
|
+
after = nil
|
21
|
+
clobber_nsum = false
|
22
|
+
|
23
|
+
ARGV.options do |x|
|
24
|
+
x.banner = usage.strip
|
25
|
+
x.separator ''
|
26
|
+
x.on('-j', '--metadata-jobs JOBS', Integer,
|
27
|
+
'Number of metadata jobs to run in parallel') { |n|
|
28
|
+
jobs = n
|
29
|
+
}
|
30
|
+
x.on('-J', '--copy-jobs JOBS', Integer,
|
31
|
+
'Number of copy jobs to run in parallel') { |n|
|
32
|
+
copy_jobs = n
|
33
|
+
}
|
34
|
+
|
35
|
+
x.on('-h', '--help', 'Show this help message.') { puts x; exit }
|
36
|
+
%w(get_file_data_timeout new_file_max_time fail_timeout timeout).each do |t|
|
37
|
+
x.on("--#{t.tr('_', '-')} SECONDS", Integer) { |n| opts[t.to_sym] = n }
|
38
|
+
end
|
39
|
+
x.on('-v', '--verbose') { @verbose += 1 }
|
40
|
+
x.on('-d', '--delete') do
|
41
|
+
begin
|
42
|
+
require 'gdbm'
|
43
|
+
require 'tempfile'
|
44
|
+
tmp = Tempfile.new(%w(mog-sync-keep .gdbm))
|
45
|
+
at_exit { tmp.close! }
|
46
|
+
keep = GDBM.new(tmp.path)
|
47
|
+
rescue LoadError
|
48
|
+
warn "gdbm extension recommended for --delete: #{e.message} (#{e.class})"
|
49
|
+
keep = {}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
x.on('-n', '--dry-run') { @dryrun = opts[:readonly] = true }
|
53
|
+
x.on('-p', '--prefix STRING') { |s| prefix = s }
|
54
|
+
x.on('--src-class STRING') { |s| src_class = s }
|
55
|
+
x.on('--dst-class STRING') { |s| dst_class = s }
|
56
|
+
x.on('--after STRING') { |s| after = s }
|
57
|
+
x.on('--max-size STRING') { |s|
|
58
|
+
mult = 1
|
59
|
+
if s.sub!(/-1\z/, "")
|
60
|
+
off = -1
|
61
|
+
elsif s.sub!(/\+1\z/, "")
|
62
|
+
off = 1
|
63
|
+
else
|
64
|
+
off = 0
|
65
|
+
end
|
66
|
+
{
|
67
|
+
/(?:K|KiB)\z/i => 1024,
|
68
|
+
/(?:M|MiB)\z/i => 1024 ** 2,
|
69
|
+
/(?:G|GiB)\z/i => 1024 ** 3,
|
70
|
+
/KB\z/i => 1000,
|
71
|
+
/MB\z/i => 1000 ** 2,
|
72
|
+
/GB/i => 1000 ** 3,
|
73
|
+
}.each do |re, m|
|
74
|
+
if s.sub!(re, "")
|
75
|
+
mult = m
|
76
|
+
break
|
77
|
+
end
|
78
|
+
end
|
79
|
+
src_maxlen = (s.to_i * mult) + off
|
80
|
+
}
|
81
|
+
x.on('-F', '--clobber-missing-checksum') { clobber_nsum = true }
|
82
|
+
x.parse!
|
83
|
+
end
|
84
|
+
|
85
|
+
@verbose = 1 if @verbose == 0 && @dryrun
|
86
|
+
ARGV.size == 2 or abort "Usage: #{usage}"
|
87
|
+
src_spec, dst_spec = ARGV
|
88
|
+
src_opts = opts.merge(readonly: true)
|
89
|
+
|
90
|
+
def client_for(str, opts = {})
|
91
|
+
trackers, domain = str.split('/', 2)
|
92
|
+
opts[:hosts] = trackers.split(/,/)
|
93
|
+
opts[:domain] = domain
|
94
|
+
MogileFS::MogileFS.new(opts)
|
95
|
+
end
|
96
|
+
|
97
|
+
# atomic for pipes/O_APPEND:
|
98
|
+
def warn(m); $stderr.syswrite("#{m}\n"); end
|
99
|
+
def echo(m); $stdout.syswrite("#{m}\n"); end
|
100
|
+
|
101
|
+
def copy(job_id, reason, src, dst, src_info, dst_info, dst_class)
|
102
|
+
key = src_info["key"]
|
103
|
+
length = src_info["length"]
|
104
|
+
unless @dryrun
|
105
|
+
opts = {
|
106
|
+
largefile: true,
|
107
|
+
class: dst_class || src_info["class"],
|
108
|
+
content_length: length,
|
109
|
+
}
|
110
|
+
|
111
|
+
# FIXME: test/support non-MD5 checksums
|
112
|
+
if /\AMD5:([a-fA-F0-9]{32})\z/ =~ src_info["checksum"]
|
113
|
+
md5 = [ $1 ].pack("H*")
|
114
|
+
opts[:content_md5] = [ md5 ].pack('m0').chomp
|
115
|
+
end
|
116
|
+
if @verbose > 1
|
117
|
+
echo "new_file(#{key}, #{opts.inspect})"
|
118
|
+
end
|
119
|
+
dst.new_file(key, opts) do |dst_io|
|
120
|
+
src.get_file_data(key, dst_io)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
if @verbose > 0
|
124
|
+
echo("#{reason} #{key}")
|
125
|
+
if @verbose > 1 && dst_info
|
126
|
+
echo "I[#{job_id}] before #{dst_info.inspect}"
|
127
|
+
echo "I[#{job_id}] after #{src_info.inspect}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
Thread.current[:mog_sync_xfer] += length
|
131
|
+
rescue => e
|
132
|
+
warn "E[#{job_id}] #{e.message} (#{e.class}) (src=#{key})"
|
133
|
+
e.backtrace { |l| warn "E[#{job_id}] #{l}" }
|
134
|
+
end
|
135
|
+
|
136
|
+
copy_queue = SizedQueue.new(copy_jobs * 8)
|
137
|
+
copiers = copy_jobs.times.map do |i|
|
138
|
+
Thread.new(i) do |job_id|
|
139
|
+
Thread.current[:mog_sync_xfer] = 0
|
140
|
+
while copy_job = copy_queue.pop
|
141
|
+
copy(job_id, *copy_job)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
queue = SizedQueue.new(jobs * 8)
|
147
|
+
consumers = jobs.times.map do |i|
|
148
|
+
Thread.new(i) do |job_id|
|
149
|
+
dst = client_for(dst_spec, opts)
|
150
|
+
src = client_for(src_spec, src_opts)
|
151
|
+
begin
|
152
|
+
key = queue.pop or break
|
153
|
+
src_info = src.file_info(key)
|
154
|
+
next if src_class && src_class != src_info["class"]
|
155
|
+
src_checksum = src_info["checksum"]
|
156
|
+
next if src_maxlen && src_info["length"] > src_maxlen
|
157
|
+
|
158
|
+
begin
|
159
|
+
# this may raise UnknownKeyError
|
160
|
+
dst_info = dst.file_info(key)
|
161
|
+
|
162
|
+
dst_checksum = dst_info["checksum"]
|
163
|
+
|
164
|
+
# maybe we need to wait for fsck to finish:
|
165
|
+
if dst_checksum == "MISSING"
|
166
|
+
warn "destination checksum broken #{dst_info.inspect} (skipped)"
|
167
|
+
next unless clobber_nsum
|
168
|
+
end
|
169
|
+
|
170
|
+
# tell user to fix source
|
171
|
+
if src_checksum == "MISSING"
|
172
|
+
warn "source checksum broken #{src_info.inspect} (skipped)"
|
173
|
+
exit_ok = false
|
174
|
+
next
|
175
|
+
end
|
176
|
+
|
177
|
+
next if dst_checksum == src_checksum
|
178
|
+
reason = "M"
|
179
|
+
rescue MogileFS::Backend::UnknownKeyError # new file
|
180
|
+
dst_info = nil
|
181
|
+
# tell user to fix source
|
182
|
+
if src_checksum == "MISSING"
|
183
|
+
warn "source checksum broken #{src_info.inspect} (copying)"
|
184
|
+
exit_ok = false
|
185
|
+
end
|
186
|
+
reason = "A"
|
187
|
+
end
|
188
|
+
copy_queue << [ reason, src, dst, src_info, dst_info, dst_class ]
|
189
|
+
rescue => e
|
190
|
+
warn "E[#{job_id}] #{e.message} (#{e.class}) (src=#{key})"
|
191
|
+
e.backtrace { |l| warn "E[#{job_id}] #{l}" }
|
192
|
+
end while true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# producer feeds consumers
|
197
|
+
begin
|
198
|
+
main_src = client_for(src_spec, src_opts)
|
199
|
+
main_src.each_key(prefix, after: after) do |key|
|
200
|
+
keep[key] = "1" if keep
|
201
|
+
queue << key
|
202
|
+
end
|
203
|
+
rescue => e
|
204
|
+
exit_ok = false
|
205
|
+
warn "Aborting due to source error: #{e.message} (#{e.class})"
|
206
|
+
e.backtrace { |l| warn "#{l}" }
|
207
|
+
end
|
208
|
+
|
209
|
+
# terminate producer threads
|
210
|
+
Thread.new { consumers.each { queue << nil } }
|
211
|
+
consumers.each { |t| t.join }
|
212
|
+
Thread.new { copiers.each { copy_queue << nil } }
|
213
|
+
copiers.each { |t| t.join }
|
214
|
+
bytes_sent = copiers.inject(0) { |sent,t| sent += t[:mog_sync_xfer] }
|
215
|
+
bytes_deleted = 0
|
216
|
+
|
217
|
+
# delete is single-threaded, it is not I/O-bound and
|
218
|
+
# we can pipeline in the future
|
219
|
+
if keep && exit_ok
|
220
|
+
queue = SizedQueue.new(8)
|
221
|
+
deleter = Thread.new do
|
222
|
+
dst = client_for(dst_spec, opts)
|
223
|
+
while key = queue.pop
|
224
|
+
begin
|
225
|
+
dst.delete(key) unless @dryrun
|
226
|
+
echo "D #{key}"
|
227
|
+
rescue MogileFS::Backend::UnknownKeyError
|
228
|
+
warn "#{key} disappeared before we could delete it"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
main_dst = client_for(dst_spec, opts)
|
233
|
+
main_dst.each_file_info(prefix, after: after) do |info|
|
234
|
+
key = info["key"]
|
235
|
+
next if keep.include?(key)
|
236
|
+
queue << key
|
237
|
+
bytes_deleted += info["length"]
|
238
|
+
end
|
239
|
+
queue << nil # terminate
|
240
|
+
deleter.join
|
241
|
+
end
|
242
|
+
if @verbose
|
243
|
+
echo "wrote #{bytes_sent} bytes, removed #{bytes_deleted} bytes"
|
244
|
+
end
|
245
|
+
exit(exit_ok)
|