Ruby mogilefs-client 3.12.2
[ruby-mogilefs-client.git] / examples / stale_fid_checker.rb
blob769ffdaa37494bc03c903f95c4473d0949b06df8
1 #!/usr/bin/env ruby
2 # This requires:
3 # * net-http-persistent RubyGem
4 # * Ruby 1.9.2+
5 # * upstream MogileFS::Server 2.45 or later
6 $stdout.sync = $stderr.sync = true
7 usage = <<EOF
8 Usage: #$0 -t TRACKERS"
10 The output of this script can be piped to awk + curl to DELETE the files:
11 #$0 -t TRACKERS | awk '{system("curl -XDELETE "$3)}'
12 EOF
14 require 'uri'
15 require 'optparse'
16 require 'mogilefs'
17 require 'net/http/persistent'
18 Thread.abort_on_exception = true
19 MogileFS::VERSION <= "3.0.0" and
20   abort "Upgrade mogilefs-client (to a version that distributes this script)" \
21         "MogileFS::Admin#each_fid is probably broken in this version"
23 trackers = []
24 ARGV.options do |x|
25   x.banner = usage.strip
26   x.separator ''
27   x.on('-t', '--trackers=host1[,host2]', '--hosts=host1[,host2]',
28        Array, 'hostnames/IP addresses of trackers') do |args|
29     trackers = args
30   end
32   x.on('-h', '--help', 'Show this help message.') { puts x; exit }
33   x.parse!
34 end
36 adm = MogileFS::Admin.new(:hosts => trackers)
37 name = File.basename($0)
38 Net::HTTP::Persistent::VERSION >= 3.0 and name = { :name => name }
39 NHP = Net::HTTP::Persistent.new(name)
40 client = MogileFS::MogileFS.new(:hosts => trackers, :domain => "none")
42 def start_perdev_thread(pfx)
43   todo = Queue.new
44   done = Queue.new
45   Thread.new do
46     while fid_path = todo.shift
47       path = "#{pfx}#{fid_path}"
48       uri = URI.parse(path)
49       begin
50         resp = NHP.request(uri, Net::HTTP::Head.new(uri.path))
51         done << [ path, resp ]
52       rescue => err
53         done << [ path, err ]
54       end
55     end
56   end
57   [ todo, done ]
58 end
60 def setup_devices(dev_map, adm)
61   hosts = {}
62   adm.get_hosts.each do |host|
63     hosts[host["hostid"]] = "http://#{host['hostip']}:#{host['http_port']}/"
64   end
66   adm.get_devices.each do |device|
67     pfx = hosts[device["hostid"]] + "dev#{device['devid']}"
68     todo, done = start_perdev_thread(pfx)
69     dev_map[todo] = done
70   end
71 end
73 def check(bad, curfid, rv)
74   path, resp = rv
75   case resp
76   when Net::HTTPNotFound # good
77   when Net::HTTPOK
78     bad << "#{curfid} #{resp.content_length} #{path}\n"
79   else
80     warn "E: #{resp.inspect} (#{resp.class}) #{path}"
81   end
82 end
84 dev_map = {}
85 setup_devices(dev_map, adm)
86 next_fid = 0
87 adm.each_fid do |fid|
88   fidid = fid["fid"]
90   if fidid != next_fid
91     (next_fid..(fidid - 1)).each do |curfid|
92       nfid = sprintf("%010u", curfid)
93       /\A(\d)(\d{3})(\d{3})(?:\d{3})\z/ =~ nfid
94       fid_path = "/#$1/#$2/#$3/#{nfid}.fid"
95       bad = []
96       dev_map.each_key { |todo| todo << fid_path }
97       dev_map.each_value { |done| check(bad, curfid, done.shift) }
98       next if bad.empty?
100       begin
101         info = client.file_debug(curfid)
102         abort "BUG: #{info.inspect} found!" if info["fid_dkey"]
103       rescue MogileFS::Backend::UnknownFidError
104       end
106       puts bad.join
107     end
108   end
109   next_fid = fidid + 1