source: trunk/src/allmydata/nodemaker.py @ e113cba

Last change on this file since e113cba was 05f48c3, checked in by meejah <meejah@…>, at 2017-06-05T22:31:41Z

Various cleanups, fixes and improvements

Squashed all commits that were meejah's between
30d68fb499f300a393fa0ced5980229f4bb6efda
and
33c268ed3a8c63a809f4403e307ecc13d848b1ab
On the branch meejah:1382.markberger-rewrite-rebase.6 as
per review

  • Property mode set to 100644
File size: 6.9 KB
Line 
1import weakref
2from zope.interface import implementer
3from allmydata.util.assertutil import precondition
4from allmydata.interfaces import INodeMaker
5from allmydata.immutable.literal import LiteralFileNode
6from allmydata.immutable.filenode import ImmutableFileNode, CiphertextFileNode
7from allmydata.immutable.upload import Data
8from allmydata.mutable.filenode import MutableFileNode
9from allmydata.mutable.publish import MutableData
10from allmydata.dirnode import DirectoryNode, pack_children
11from allmydata.unknown import UnknownNode
12from allmydata.blacklist import ProhibitedNode
13from allmydata import uri
14
15
16@implementer(INodeMaker)
17class NodeMaker(object):
18
19    def __init__(self, storage_broker, secret_holder, history,
20                 uploader, terminator,
21                 default_encoding_parameters, mutable_file_default,
22                 key_generator, blacklist=None):
23        self.storage_broker = storage_broker
24        self.secret_holder = secret_holder
25        self.history = history
26        self.uploader = uploader
27        self.terminator = terminator
28        self.default_encoding_parameters = default_encoding_parameters
29        self.mutable_file_default = mutable_file_default
30        self.key_generator = key_generator
31        self.blacklist = blacklist
32
33        self._node_cache = weakref.WeakValueDictionary() # uri -> node
34
35    def _create_lit(self, cap):
36        return LiteralFileNode(cap)
37    def _create_immutable(self, cap):
38        return ImmutableFileNode(cap, self.storage_broker, self.secret_holder,
39                                 self.terminator, self.history)
40    def _create_immutable_verifier(self, cap):
41        return CiphertextFileNode(cap, self.storage_broker, self.secret_holder,
42                                  self.terminator, self.history)
43    def _create_mutable(self, cap):
44        n = MutableFileNode(self.storage_broker, self.secret_holder,
45                            self.default_encoding_parameters,
46                            self.history)
47        return n.init_from_cap(cap)
48    def _create_dirnode(self, filenode):
49        return DirectoryNode(filenode, self, self.uploader)
50
51    def create_from_cap(self, writecap, readcap=None, deep_immutable=False, name=u"<unknown name>"):
52        # this returns synchronously. It starts with a "cap string".
53        assert isinstance(writecap, (str, type(None))), type(writecap)
54        assert isinstance(readcap,  (str, type(None))), type(readcap)
55
56        bigcap = writecap or readcap
57        if not bigcap:
58            # maybe the writecap was hidden because we're in a readonly
59            # directory, and the future cap format doesn't have a readcap, or
60            # something.
61            return UnknownNode(None, None)  # deep_immutable and name not needed
62
63        # The name doesn't matter for caching since it's only used in the error
64        # attribute of an UnknownNode, and we don't cache those.
65        if deep_immutable:
66            memokey = "I" + bigcap
67        else:
68            memokey = "M" + bigcap
69        if memokey in self._node_cache:
70            node = self._node_cache[memokey]
71        else:
72            cap = uri.from_string(bigcap, deep_immutable=deep_immutable,
73                                  name=name)
74            node = self._create_from_single_cap(cap)
75
76            # node is None for an unknown URI, otherwise it is a type for which
77            # is_mutable() is known. We avoid cacheing mutable nodes due to
78            # ticket #1679.
79            if node is None:
80                # don't cache UnknownNode
81                node = UnknownNode(writecap, readcap,
82                                   deep_immutable=deep_immutable, name=name)
83            elif node.is_mutable():
84                self._node_cache[memokey] = node  # note: WeakValueDictionary
85
86        if self.blacklist:
87            si = node.get_storage_index()
88            # if this node is blacklisted, return the reason, otherwise return None
89            reason = self.blacklist.check_storageindex(si)
90            if reason is not None:
91                # The original node object is cached above, not the ProhibitedNode wrapper.
92                # This ensures that removing the blacklist entry will make the node
93                # accessible if create_from_cap is called again.
94                node = ProhibitedNode(node, reason)
95        return node
96
97    def _create_from_single_cap(self, cap):
98        if isinstance(cap, uri.LiteralFileURI):
99            return self._create_lit(cap)
100        if isinstance(cap, uri.CHKFileURI):
101            return self._create_immutable(cap)
102        if isinstance(cap, uri.CHKFileVerifierURI):
103            return self._create_immutable_verifier(cap)
104        if isinstance(cap, (uri.ReadonlySSKFileURI, uri.WriteableSSKFileURI,
105                            uri.WriteableMDMFFileURI, uri.ReadonlyMDMFFileURI)):
106            return self._create_mutable(cap)
107        if isinstance(cap, (uri.DirectoryURI,
108                            uri.ReadonlyDirectoryURI,
109                            uri.ImmutableDirectoryURI,
110                            uri.LiteralDirectoryURI,
111                            uri.MDMFDirectoryURI,
112                            uri.ReadonlyMDMFDirectoryURI)):
113            filenode = self._create_from_single_cap(cap.get_filenode_cap())
114            return self._create_dirnode(filenode)
115        return None
116
117    def create_mutable_file(self, contents=None, keysize=None, version=None):
118        if version is None:
119            version = self.mutable_file_default
120        n = MutableFileNode(self.storage_broker, self.secret_holder,
121                            self.default_encoding_parameters, self.history)
122        d = self.key_generator.generate(keysize)
123        d.addCallback(n.create_with_keys, contents, version=version)
124        d.addCallback(lambda res: n)
125        return d
126
127    def create_new_mutable_directory(self, initial_children={}, version=None):
128        # initial_children must have metadata (i.e. {} instead of None)
129        for (name, (node, metadata)) in initial_children.iteritems():
130            precondition(isinstance(metadata, dict),
131                         "create_new_mutable_directory requires metadata to be a dict, not None", metadata)
132            node.raise_error()
133        d = self.create_mutable_file(lambda n:
134                                     MutableData(pack_children(initial_children,
135                                                    n.get_writekey())),
136                                     version=version)
137        d.addCallback(self._create_dirnode)
138        return d
139
140    def create_immutable_directory(self, children, convergence=None):
141        if convergence is None:
142            convergence = self.secret_holder.get_convergence_secret()
143        packed = pack_children(children, None, deep_immutable=True)
144        uploadable = Data(packed, convergence)
145        # XXX should pass reactor arg
146        d = self.uploader.upload(uploadable)
147        d.addCallback(lambda results:
148                      self.create_from_cap(None, results.get_uri()))
149        d.addCallback(self._create_dirnode)
150        return d
Note: See TracBrowser for help on using the repository browser.