Teach 'tahoe debug catalog-shares about MDMF. Closes #1507.
authorBrian Warner <warner@lothar.com>
Sun, 28 Aug 2011 08:09:31 +0000 (01:09 -0700)
committerBrian Warner <warner@lothar.com>
Sun, 28 Aug 2011 08:09:31 +0000 (01:09 -0700)
src/allmydata/scripts/debug.py
src/allmydata/test/test_mutable.py

index a507b7cfe15777f0a0105766b6a6adfd1539e0e2..16e57b33dce3ea2e489e6f4c8b31d599bac15ca6 100644 (file)
@@ -728,9 +728,12 @@ def describe_share(abs_sharefile, si_s, shnum_s, now, out):
 
         share_type = "unknown"
         f.seek(m.DATA_OFFSET)
-        if f.read(1) == "\x00":
+        version = f.read(1)
+        if version == "\x00":
             # this slot contains an SMDF share
             share_type = "SDMF"
+        elif version == "\x01":
+            share_type = "MDMF"
 
         if share_type == "SDMF":
             f.seek(m.DATA_OFFSET)
@@ -752,6 +755,35 @@ def describe_share(abs_sharefile, si_s, shnum_s, now, out):
                   (si_s, k, N, datalen,
                    seqnum, base32.b2a(root_hash),
                    expiration, quote_output(abs_sharefile))
+        elif share_type == "MDMF":
+            from allmydata.mutable.layout import MDMFSlotReadProxy
+            fake_shnum = 0
+            # TODO: factor this out with dump_MDMF_share()
+            class ShareDumper(MDMFSlotReadProxy):
+                def _read(self, readvs, force_remote=False, queue=False):
+                    data = []
+                    for (where,length) in readvs:
+                        f.seek(m.DATA_OFFSET+where)
+                        data.append(f.read(length))
+                    return defer.succeed({fake_shnum: data})
+
+            p = ShareDumper(None, "fake-si", fake_shnum)
+            def extract(func):
+                stash = []
+                # these methods return Deferreds, but we happen to know that
+                # they run synchronously when not actually talking to a
+                # remote server
+                d = func()
+                d.addCallback(stash.append)
+                return stash[0]
+
+            verinfo = extract(p.get_verinfo)
+            (seqnum, root_hash, salt_to_use, segsize, datalen, k, N, prefix,
+             offsets) = verinfo
+            print >>out, "MDMF %s %d/%d %d #%d:%s %d %s" % \
+                  (si_s, k, N, datalen,
+                   seqnum, base32.b2a(root_hash),
+                   expiration, quote_output(abs_sharefile))
         else:
             print >>out, "UNKNOWN mutable %s" % quote_output(abs_sharefile)
 
index 45622220fdd90567edab7982dfa460e63bfa6067..6a4af6c02227b608d979b7bc8e9e5c7140784c24 100644 (file)
@@ -2990,6 +2990,26 @@ class Version(GridTestMixin, unittest.TestCase, testutil.ShouldFailMixin, \
             self.failUnless("  datalen: %d" % len(self.data) in lines, output)
             vcap = n.get_verify_cap().to_string()
             self.failUnless("  verify-cap: %s" % vcap in lines, output)
+
+            cso = debug.CatalogSharesOptions()
+            cso.nodedirs = fso.nodedirs
+            cso.stdout = StringIO()
+            cso.stderr = StringIO()
+            debug.catalog_shares(cso)
+            shares = cso.stdout.getvalue().splitlines()
+            oneshare = shares[0] # all shares should be MDMF
+            self.failIf(oneshare.startswith("UNKNOWN"), oneshare)
+            self.failUnless(oneshare.startswith("MDMF"), oneshare)
+            fields = oneshare.split()
+            self.failUnlessEqual(fields[0], "MDMF")
+            self.failUnlessEqual(fields[1], storage_index)
+            self.failUnlessEqual(fields[2], "3/10")
+            self.failUnlessEqual(fields[3], "%d" % len(self.data))
+            self.failUnless(fields[4].startswith("#1:"), fields[3])
+            # the rest of fields[4] is the roothash, which depends upon
+            # encryption salts and is not constant. fields[5] is the
+            # remaining time on the longest lease, which is timing dependent.
+            # The rest of the line is the quoted pathname to the share.
         d.addCallback(_debug)
         return d