3 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
4 from allmydata.scripts.common_http import do_http
5 from allmydata.util import base32
6 from allmydata import uri
10 class SlowOperationRunner:
12 def run(self, options):
13 stderr = options.stderr
14 self.options = options
15 self.ophandle = ophandle = base32.b2a(os.urandom(16))
16 nodeurl = options['node-url']
17 if not nodeurl.endswith("/"):
19 self.nodeurl = nodeurl
21 rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS)
24 url = nodeurl + "uri/%s" % urllib.quote(rootcap)
26 url += "/" + escape_path(path)
27 # todo: should it end with a slash?
28 url += "?t=%s&ophandle=%s" % (self.operation, ophandle)
29 resp = do_http("POST", url)
30 if resp.status not in (200, 302):
31 print >>stderr, "ERROR", resp.status, resp.reason, resp.read()
33 # now we poll for results. We nominally poll at t=1, 5, 10, 30, 60,
34 # 90, k*120 seconds, but if the poll takes non-zero time, that will
35 # be slightly longer. I'm not worried about trying to make up for
38 return self.wait_for_results()
41 for i in (1,5,10,30,60,90):
48 def wait_for_results(self):
50 for next in self.poll_times():
58 url = self.nodeurl + "operations/" + self.ophandle
59 url += "?t=status&output=JSON&release-after-complete=true"
60 stdout = self.options.stdout
61 stderr = self.options.stderr
62 resp = do_http("GET", url)
63 if resp.status != 200:
64 print >>stderr, "ERROR", resp.status, resp.reason, resp.read()
66 data = simplejson.loads(resp.read())
67 if not data["finished"]:
69 self.write_results(data)
72 class ManifestGrabber(SlowOperationRunner):
73 operation = "start-manifest"
75 def write_results(self, data):
76 stdout = self.options.stdout
77 stderr = self.options.stderr
78 if self.options["storage-index"]:
79 for (path, cap) in data["manifest"]:
80 u = uri.from_string(str(cap))
81 si = u.get_storage_index()
83 print >>stdout, base32.b2a(si)
85 for (path, cap) in data["manifest"]:
87 print >>stdout, cap, "/".join(path)
88 except UnicodeEncodeError:
89 print >>stdout, cap, "/".join([p.encode("utf-8")
92 def manifest(options):
93 return ManifestGrabber().run(options)
95 class StatsGrabber(SlowOperationRunner):
96 operation = "start-deep-stats"
98 def write_results(self, data):
99 stdout = self.options.stdout
100 stderr = self.options.stderr
101 keys = ("count-immutable-files",
102 "count-mutable-files",
103 "count-literal-files",
106 "size-immutable-files",
107 "size-mutable-files",
108 "size-literal-files",
111 "largest-immutable-files",
113 width = max([len(k) for k in keys])
114 print >>stdout, "Counts and Total Sizes:"
116 fmt = "%" + str(width) + "s: %d"
118 print >>stdout, fmt % (k, data[k])
119 print >>stdout, "Size Histogram:"
121 maxlen = max([len(str(maxsize))
122 for (minsize, maxsize, count)
123 in data["size-files-histogram"]])
124 minfmt = "%" + str(maxlen) + "d"
125 maxfmt = "%-" + str(maxlen) + "d"
126 linefmt = minfmt + "-" + maxfmt + " : %d"
127 for (minsize, maxsize, count) in data["size-files-histogram"]:
128 if prevmax is not None and minsize != prevmax+1:
129 print >>stdout, " "*(maxlen-1) + "..."
131 print >>stdout, linefmt % (minsize, maxsize, count)
134 return StatsGrabber().run(options)