From bc53c240031bc77d6dc3040918fb0d70098191d9 Mon Sep 17 00:00:00 2001 From: Brian Warner <warner@allmydata.com> Date: Mon, 24 Nov 2008 14:40:46 -0700 Subject: [PATCH] dirnode manifest: add verifycaps, both to internal API and to webapi. This will give the manual-GC tools more to work with, so they can estimate how much space will be freed. --- docs/CLI.txt | 5 ++++- docs/frontends/webapi.txt | 3 ++- src/allmydata/dirnode.py | 5 +++++ src/allmydata/interfaces.py | 9 ++++++--- src/allmydata/test/test_dirnode.py | 18 ++++++++++++++++-- src/allmydata/test/test_system.py | 23 +++++++++++++++++++++++ src/allmydata/test/test_web.py | 1 + src/allmydata/web/directory.py | 8 +++++--- 8 files changed, 62 insertions(+), 10 deletions(-) diff --git a/docs/CLI.txt b/docs/CLI.txt index 93ab4f87..f88464c6 100644 --- a/docs/CLI.txt +++ b/docs/CLI.txt @@ -329,6 +329,7 @@ tahoe mv tahoe:uploaded.txt fun:uploaded.txt tahoe manifest tahoe: tahoe manifest --storage-index tahoe: +tahoe manifest --raw tahoe: This performs a recursive walk of the given directory, visiting every file and directory that can be reached from that point. It then emits one line to @@ -339,7 +340,9 @@ tahoe manifest --storage-index tahoe: If --storage-index is added, each line will instead contain the object's storage index. This (string) value is useful to determine which share files - (on the server) are associated with this directory tree. + (on the server) are associated with this directory tree. If --raw is + provided instead, the output will be a JSON-encoded dictionary that includes + keys for storage index strings, verifycaps, and deep-stats. tahoe stats tahoe: diff --git a/docs/frontends/webapi.txt b/docs/frontends/webapi.txt index 500fc3d2..5ec59067 100644 --- a/docs/frontends/webapi.txt +++ b/docs/frontends/webapi.txt @@ -964,11 +964,12 @@ POST $DIRURL?t=start-manifest (must add &ophandle=XYZ) by a space. If output=JSON is added to the queryargs, then the results will be a - JSON-formatted dictionary with five keys: + JSON-formatted dictionary with six keys: finished (bool): if False then you must reload the page until True origin_si (base32 str): the storage index of the starting point manifest: list of (path, cap) tuples, where path is a list of strings. + verifycaps: list of (printable) verify cap strings storage-index: list of (base32) storage index strings stats: a dictionary with the same keys as the t=deep-stats command (described below) diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py index a485a24e..b976dbff 100644 --- a/src/allmydata/dirnode.py +++ b/src/allmydata/dirnode.py @@ -641,17 +641,22 @@ class ManifestWalker(DeepStats): DeepStats.__init__(self, origin) self.manifest = [] self.storage_index_strings = set() + self.verifycaps = set() def add_node(self, node, path): self.manifest.append( (tuple(path), node.get_uri()) ) si = node.get_storage_index() if si: self.storage_index_strings.add(base32.b2a(si)) + v = node.get_verifier() + if v: + self.verifycaps.add(v.to_string()) return DeepStats.add_node(self, node, path) def get_results(self): stats = DeepStats.get_results(self) return {"manifest": self.manifest, + "verifycaps": self.verifycaps, "storage-index": self.storage_index_strings, "stats": stats, } diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py index 47f7afba..5b935be4 100644 --- a/src/allmydata/interfaces.py +++ b/src/allmydata/interfaces.py @@ -863,16 +863,19 @@ class IDirectoryNode(IMutableFilesystemNode): I also compute deep-stats as described below. I return a Monitor. The Monitor's results will be a dictionary with - three elements: + four elements: res['manifest']: a list of (path, cap) tuples for all nodes (directories and files) reachable from this one. 'path' will be a tuple of unicode strings. The origin dirnode will be represented by an empty path tuple. + res['verifycaps']: a list of (printable) verifycap strings, one for + each reachable non-LIT node. This is a set: + it will contain no duplicates. res['storage-index']: a list of (base32) storage index strings, - one for each reachable node. This is a set: - duplicates have been removed. + one for each reachable non-LIT node. This is + a set: it will contain no duplicates. res['stats']: a dictionary, the same that is generated by start_deep_stats() below. diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py index cc2be476..b1dd67f0 100644 --- a/src/allmydata/test/test_dirnode.py +++ b/src/allmydata/test/test_dirnode.py @@ -9,7 +9,7 @@ from allmydata.interfaces import IURI, IClient, IMutableFileNode, \ INewDirectoryURI, IReadonlyNewDirectoryURI, IFileNode, \ ExistingChildError, NoSuchChildError, \ IDeepCheckResults, IDeepCheckAndRepairResults -from allmydata.util import hashutil +from allmydata.util import hashutil, base32 from allmydata.monitor import Monitor from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \ FakeDirectoryNode, create_chk_filenode, ErrorMixin @@ -281,6 +281,8 @@ class Dirnode(unittest.TestCase, def test_create(self): self.expected_manifest = [] + self.expected_verifycaps = set() + self.expected_storage_indexes = set() d = self.client.create_empty_dirnode() def _then(n): @@ -294,8 +296,11 @@ class Dirnode(unittest.TestCase, u_v = n.get_verifier().to_string() self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v) self.expected_manifest.append( ((), u) ) + self.expected_verifycaps.add(u_v) + si = n.get_storage_index() + self.expected_storage_indexes.add(base32.b2a(si)) expected_si = n._uri._filenode_uri.storage_index - self.failUnlessEqual(n.get_storage_index(), expected_si) + self.failUnlessEqual(si, expected_si) d = n.list() d.addCallback(lambda res: self.failUnlessEqual(res, {})) @@ -306,6 +311,8 @@ class Dirnode(unittest.TestCase, m = Marker(fake_file_uri) ffu_v = m.get_verifier().to_string() self.expected_manifest.append( ((u"child",) , m.get_uri()) ) + self.expected_verifycaps.add(ffu_v) + self.expected_storage_indexes.add(base32.b2a(m.get_storage_index())) d.addCallback(lambda res: n.set_uri(u"child", fake_file_uri)) d.addCallback(lambda res: self.shouldFail(ExistingChildError, "set_uri-no", @@ -326,6 +333,9 @@ class Dirnode(unittest.TestCase, new_v = subdir.get_verifier().to_string() assert isinstance(new_v, str) self.expected_manifest.append( ((u"subdir",), subdir.get_uri()) ) + self.expected_verifycaps.add(new_v) + si = subdir.get_storage_index() + self.expected_storage_indexes.add(base32.b2a(si)) d.addCallback(_created) d.addCallback(lambda res: @@ -372,6 +382,10 @@ class Dirnode(unittest.TestCase, sorted(self.expected_manifest)) stats = res["stats"] _check_deepstats(stats) + self.failUnlessEqual(self.expected_verifycaps, + res["verifycaps"]) + self.failUnlessEqual(self.expected_storage_indexes, + res["storage-index"]) d.addCallback(_check_manifest) def _add_subsubdir(res): diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py index c46b552d..a3c564b4 100644 --- a/src/allmydata/test/test_system.py +++ b/src/allmydata/test/test_system.py @@ -2423,6 +2423,7 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): "--node-directory", basedir, "--storage-index", self.root_uri])) def _check2((out,err)): + self.failUnlessEqual(err, "") lines = [l for l in out.split("\n") if l] self.failUnlessEqual(len(lines), 3) self.failUnless(base32.b2a(self.root.get_storage_index()) in lines) @@ -2430,6 +2431,28 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase): self.failUnless(base32.b2a(self.large.get_storage_index()) in lines) d.addCallback(_check2) + d.addCallback(lambda res: + self._run_cli(["manifest", + "--node-directory", basedir, + "--raw", self.root_uri])) + def _check2r((out,err)): + self.failUnlessEqual(err, "") + data = simplejson.loads(out) + sis = data["storage-index"] + self.failUnlessEqual(len(sis), 3) + self.failUnless(base32.b2a(self.root.get_storage_index()) in sis) + self.failUnless(base32.b2a(self.mutable.get_storage_index()) in sis) + self.failUnless(base32.b2a(self.large.get_storage_index()) in sis) + self.failUnlessEqual(data["stats"]["count-files"], 4) + self.failUnlessEqual(data["origin"], + base32.b2a(self.root.get_storage_index())) + verifycaps = data["verifycaps"] + self.failUnlessEqual(len(verifycaps), 3) + self.failUnless(self.root.get_verifier().to_string() in verifycaps) + self.failUnless(self.mutable.get_verifier().to_string() in verifycaps) + self.failUnless(self.large.get_verifier().to_string() in verifycaps) + d.addCallback(_check2r) + d.addCallback(lambda res: self._run_cli(["stats", "--node-directory", basedir, diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 019049bd..2a9d770d 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -950,6 +950,7 @@ class Web(WebMixin, testutil.StallMixin, unittest.TestCase): self.failUnless("finished" in res) self.failUnless("origin" in res) self.failUnless("storage-index" in res) + self.failUnless("verifycaps" in res) self.failUnless("stats" in res) d.addCallback(_got_json) return d diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py index 1e3920f8..648484c4 100644 --- a/src/allmydata/web/directory.py +++ b/src/allmydata/web/directory.py @@ -731,9 +731,11 @@ class ManifestResults(rend.Page, ReloadMixin): def json(self, ctx): inevow.IRequest(ctx).setHeader("content-type", "text/plain") m = self.monitor - status = {"manifest": m.get_status()["manifest"], - "storage-index": list(m.get_status()["storage-index"]), - "stats": m.get_status()["stats"], + s = m.get_status() + status = {"manifest": s["manifest"], + "verifycaps": list(s["verifycaps"]), + "storage-index": list(s["storage-index"]), + "stats": s["stats"], "finished": m.is_finished(), "origin": base32.b2a(m.origin_si), } -- 2.45.2