mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-20 09:46:18 +00:00
dirnode: add build_manifest() and introduce 'refresh capabilities'
This commit is contained in:
parent
2766b7988b
commit
18ab5ce837
@ -329,6 +329,39 @@ class ImmutableDirectoryNode:
|
||||
d.addCallback(lambda child: self.delete(current_child_name))
|
||||
return d
|
||||
|
||||
def build_manifest(self):
|
||||
# given a dirnode, construct a list refresh-capabilities for all the
|
||||
# nodes it references.
|
||||
|
||||
# this is just a tree-walker, except that following each edge
|
||||
# requires a Deferred.
|
||||
|
||||
manifest = set()
|
||||
manifest.add(self.get_refresh_capability())
|
||||
|
||||
d = self._build_manifest_from_node(self, manifest)
|
||||
d.addCallback(lambda res: manifest)
|
||||
return d
|
||||
|
||||
def _build_manifest_from_node(self, node, manifest):
|
||||
d = node.list()
|
||||
def _got_list(res):
|
||||
dl = []
|
||||
for name, child in res.iteritems():
|
||||
manifest.add(child.get_refresh_capability())
|
||||
if IDirectoryNode.providedBy(child):
|
||||
dl.append(self._build_manifest_from_node(child, manifest))
|
||||
if dl:
|
||||
return defer.DeferredList(dl)
|
||||
d.addCallback(_got_list)
|
||||
return d
|
||||
|
||||
def get_refresh_capability(self):
|
||||
ro_uri = self.get_immutable_uri()
|
||||
furl, rk = uri.unpack_dirnode_uri(ro_uri)
|
||||
wk, we, rk, index = hashutil.generate_dirnode_keys_from_readkey(rk)
|
||||
return "DIR-REFRESH:%s" % idlib.b2a(index)
|
||||
|
||||
class MutableDirectoryNode(ImmutableDirectoryNode):
|
||||
implements(IDirectoryNode)
|
||||
|
||||
@ -372,6 +405,10 @@ class FileNode:
|
||||
return cmp(self.__class__, them.__class__)
|
||||
return cmp(self.uri, them.uri)
|
||||
|
||||
def get_refresh_capability(self):
|
||||
d = uri.unpack_uri(self.uri)
|
||||
return "CHK-REFRESH:%s" % idlib.b2a(d['storage_index'])
|
||||
|
||||
def download(self, target):
|
||||
downloader = self._client.getServiceNamed("downloader")
|
||||
return downloader.download(self.uri, target)
|
||||
|
@ -206,10 +206,22 @@ class IFileNode(Interface):
|
||||
def download_to_data():
|
||||
pass
|
||||
|
||||
def get_uri():
|
||||
"""Return the URI that can be used by others to get access to this
|
||||
file.
|
||||
"""
|
||||
|
||||
def get_refresh_capability():
|
||||
"""Return a string that represents the 'refresh capability' for this
|
||||
node. The holder of this capability will be able to renew the lease
|
||||
for this node, protecting it from garbage-collection.
|
||||
"""
|
||||
|
||||
class IDirectoryNode(Interface):
|
||||
def is_mutable():
|
||||
"""Return True if this directory is mutable, False if it is read-only.
|
||||
"""
|
||||
|
||||
def get_uri():
|
||||
"""Return the directory URI that can be used by others to get access
|
||||
to this directory node. If this node is read-only, the URI will only
|
||||
@ -219,10 +231,11 @@ class IDirectoryNode(Interface):
|
||||
If you have read-write access to a directory and wish to share merely
|
||||
read-only access with others, use get_immutable_uri().
|
||||
|
||||
The dirnode ('1') URI returned by this method can be used in set() on
|
||||
a different directory ('2') to 'mount' a reference to this directory
|
||||
('1') under the other ('2'). This URI is just a string, so it can be
|
||||
passed around through email or other out-of-band protocol.
|
||||
The dirnode ('1') URI returned by this method can be used in
|
||||
set_uri() on a different directory ('2') to 'mount' a reference to
|
||||
this directory ('1') under the other ('2'). This URI is just a
|
||||
string, so it can be passed around through email or other out-of-band
|
||||
protocol.
|
||||
"""
|
||||
|
||||
def get_immutable_uri():
|
||||
@ -234,6 +247,12 @@ class IDirectoryNode(Interface):
|
||||
get_immutable_uri() will return the same thing as get_uri().
|
||||
"""
|
||||
|
||||
def get_refresh_capability():
|
||||
"""Return a string that represents the 'refresh capability' for this
|
||||
node. The holder of this capability will be able to renew the lease
|
||||
for this node, protecting it from garbage-collection.
|
||||
"""
|
||||
|
||||
def list():
|
||||
"""I return a Deferred that fires with a dictionary mapping child
|
||||
name to an IFileNode or IDirectoryNode."""
|
||||
@ -280,6 +299,9 @@ class IDirectoryNode(Interface):
|
||||
'new_child_name', which defaults to 'current_child_name'. I return a
|
||||
Deferred that fires when the operation finishes."""
|
||||
|
||||
def build_manifest():
|
||||
"""Return a set of refresh-capabilities for all nodes (directories
|
||||
and files) reachable from this one."""
|
||||
|
||||
class ICodecEncoder(Interface):
|
||||
def set_params(data_size, required_shares, max_shares):
|
||||
|
@ -173,8 +173,8 @@ class Test(unittest.TestCase):
|
||||
self.failUnlessEqual(res, {})
|
||||
d.addCallback(_listed)
|
||||
|
||||
file1 = uri.pack_uri("i"*32, "k"*16, "e"*32, 25, 100, 12345)
|
||||
file2 = uri.pack_uri("i"*31 + "2", "k"*16, "e"*32, 25, 100, 12345)
|
||||
file1 = uri.pack_uri("11" + " "*30, "k"*16, "e"*32, 25, 100, 12345)
|
||||
file2 = uri.pack_uri("2i" + " "*30, "k"*16, "e"*32, 25, 100, 12345)
|
||||
file2_node = dirnode.FileNode(file2, None)
|
||||
d.addCallback(lambda res: rootnode.set_uri("foo", file1))
|
||||
# root/
|
||||
@ -184,6 +184,7 @@ class Test(unittest.TestCase):
|
||||
def _listed2(res):
|
||||
self.failUnlessEqual(res.keys(), ["foo"])
|
||||
file1_node = res["foo"]
|
||||
self.file1_node = file1_node
|
||||
self.failUnless(isinstance(file1_node, dirnode.FileNode))
|
||||
self.failUnlessEqual(file1_node.uri, file1)
|
||||
d.addCallback(_listed2)
|
||||
@ -238,6 +239,10 @@ class Test(unittest.TestCase):
|
||||
d.addCallback(self.failUnlessIdentical, file2_node)
|
||||
# and a directory
|
||||
d.addCallback(lambda res: self.bar_node.create_empty_directory("baz"))
|
||||
def _added_baz(baz_node):
|
||||
self.failUnless(IDirectoryNode.providedBy(baz_node))
|
||||
self.baz_node = baz_node
|
||||
d.addCallback(_added_baz)
|
||||
# root/
|
||||
# root/foo =file1
|
||||
# root/bar/
|
||||
@ -257,6 +262,21 @@ class Test(unittest.TestCase):
|
||||
d.addCallback(lambda res:
|
||||
self.failIf(res["baz"].is_mutable()))
|
||||
|
||||
# test the manifest
|
||||
d.addCallback(lambda res: self.rootnode.build_manifest())
|
||||
def _check_manifest(manifest):
|
||||
manifest = sorted(list(manifest))
|
||||
self.failUnlessEqual(len(manifest), 5)
|
||||
expected = [self.rootnode.get_refresh_capability(),
|
||||
self.bar_node.get_refresh_capability(),
|
||||
self.file1_node.get_refresh_capability(),
|
||||
file2_node.get_refresh_capability(),
|
||||
self.baz_node.get_refresh_capability(),
|
||||
]
|
||||
expected.sort()
|
||||
self.failUnlessEqual(manifest, expected)
|
||||
d.addCallback(_check_manifest)
|
||||
|
||||
# try to add a file to bar-ro, should get exception
|
||||
d.addCallback(lambda res:
|
||||
self.bar_node_readonly.set_uri("file3", file2))
|
||||
@ -290,7 +310,7 @@ class Test(unittest.TestCase):
|
||||
self.bar_node.move_child_to("file2",
|
||||
self.rootnode, "file4"))
|
||||
# root/
|
||||
# root/file4 = file4
|
||||
# root/file4 = file2
|
||||
# root/bar/
|
||||
# root/bar/baz/
|
||||
# root/bar-ro/ (read-only)
|
||||
@ -327,6 +347,27 @@ class Test(unittest.TestCase):
|
||||
d.addCallback(self.failUnlessKeysMatch, ["baz", "file4"])
|
||||
d.addCallback(lambda res:self.bar_node_readonly.list())
|
||||
d.addCallback(self.failUnlessKeysMatch, ["baz", "file4"])
|
||||
# root/
|
||||
# root/bar/
|
||||
# root/bar/file4 = file2
|
||||
# root/bar/baz/
|
||||
# root/bar-ro/ (read-only)
|
||||
# root/bar-ro/file4 = file2
|
||||
# root/bar-ro/baz/
|
||||
|
||||
# test the manifest
|
||||
d.addCallback(lambda res: self.rootnode.build_manifest())
|
||||
def _check_manifest2(manifest):
|
||||
manifest = sorted(list(manifest))
|
||||
self.failUnlessEqual(len(manifest), 4)
|
||||
expected = [self.rootnode.get_refresh_capability(),
|
||||
self.bar_node.get_refresh_capability(),
|
||||
file2_node.get_refresh_capability(),
|
||||
self.baz_node.get_refresh_capability(),
|
||||
]
|
||||
expected.sort()
|
||||
self.failUnlessEqual(manifest, expected)
|
||||
d.addCallback(_check_manifest2)
|
||||
|
||||
d.addCallback(self._test_one_3)
|
||||
return d
|
||||
|
Loading…
x
Reference in New Issue
Block a user