]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
dirnode: add set_uris() and set_nodes() (plural), to set multiple children at once...
authorBrian Warner <warner@allmydata.com>
Wed, 19 Dec 2007 06:30:02 +0000 (23:30 -0700)
committerBrian Warner <warner@allmydata.com>
Wed, 19 Dec 2007 06:30:02 +0000 (23:30 -0700)
src/allmydata/dirnode.py
src/allmydata/interfaces.py
src/allmydata/test/test_web.py

index 0659d687a6ced75cbad438dc97976b72faeda00f..6efdc1d3521890ca90e339f596b4203916a81e8f 100644 (file)
@@ -6,7 +6,7 @@ from twisted.internet import defer
 import simplejson
 from allmydata.mutable import NotMutableError
 from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
-     IURI, IFileNode, IMutableFileURI, IVerifierURI
+     IURI, IFileNode, IMutableFileURI, IVerifierURI, IFilesystemNode
 from allmydata.util import hashutil
 from allmydata.util.hashutil import netstring
 from allmydata.uri import NewDirectoryURI
@@ -131,7 +131,7 @@ class NewDirectoryNode:
             child, metadata = children[name]
             assert (IFileNode.providedBy(child)
                     or IMutableFileNode.providedBy(child)
-                    or IDirectoryNode.providedBy(child)), children
+                    or IDirectoryNode.providedBy(child)), (name,child)
             assert isinstance(metadata, dict)
             rwcap = child.get_uri() # might be RO if the child is not writeable
             rocap = child.get_readonly_uri()
@@ -224,7 +224,20 @@ class NewDirectoryNode:
 
         If this directory node is read-only, the Deferred will errback with a
         NotMutableError."""
-        return self.set_node(name, self._create_node(child_uri), metadata, wait_for_numpeers=wait_for_numpeers)
+        return self.set_node(name, self._create_node(child_uri), metadata,
+                             wait_for_numpeers)
+
+    def set_uris(self, entries, wait_for_numpeers=None):
+        node_entries = []
+        for e in entries:
+            if len(e) == 2:
+                name, child_uri = e
+                metadata = {}
+            else:
+                assert len(e) == 3
+                name, child_uri, metadata = e
+            node_entries.append( (name,self._create_node(child_uri),metadata) )
+        return self.set_nodes(node_entries, wait_for_numpeers)
 
     def set_node(self, name, child, metadata={}, wait_for_numpeers=None):
         """I add a child at the specific name. I return a Deferred that fires
@@ -234,17 +247,31 @@ class NewDirectoryNode:
 
         If this directory node is read-only, the Deferred will errback with a
         NotMutableError."""
+        assert IFilesystemNode.providedBy(child), child
+        d = self.set_nodes( [(name, child, metadata)], wait_for_numpeers)
+        d.addCallback(lambda res: child)
+        return d
+
+    def set_nodes(self, entries, wait_for_numpeers=None):
         if self.is_readonly():
             return defer.fail(NotMutableError())
         d = self._read()
         def _add(children):
-            children[name] = (child, metadata)
+            for e in entries:
+                if len(e) == 2:
+                    name, child = e
+                    metadata = {}
+                else:
+                    assert len(e) == 3
+                    name, child, metadata = e
+                children[name] = (child, metadata)
             new_contents = self._pack_contents(children)
             return self._node.replace(new_contents, wait_for_numpeers=wait_for_numpeers)
         d.addCallback(_add)
-        d.addCallback(lambda res: child)
+        d.addCallback(lambda res: None)
         return d
 
+
     def add_file(self, name, uploadable, wait_for_numpeers=None):
         """I upload a file (using the given IUploadable), then attach the
         resulting FileNode to the directory at the given name. I return a
index f8ef5acd2e8eb9484012234760fe9452bba389b5..48de0abe456d9eafcf84608c9d5bb3ab7fed9de1 100644 (file)
@@ -530,6 +530,13 @@ class IDirectoryNode(IMutableFilesystemNode):
         If this directory node is read-only, the Deferred will errback with a
         NotMutableError."""
 
+    def set_uris(entries):
+        """Add multiple (name, child_uri) pairs to a directory node. Returns
+        a Deferred that fires (with None) when the operation finishes. This
+        is equivalent to calling set_uri() multiple times, but is much more
+        efficient.
+        """
+
     def set_node(name, child):
         """I add a child at the specific name. I return a Deferred that fires
         when the operation finishes. This Deferred will fire with the child
@@ -539,6 +546,13 @@ class IDirectoryNode(IMutableFilesystemNode):
         If this directory node is read-only, the Deferred will errback with a
         NotMutableError."""
 
+    def set_nodes(entries):
+        """Add multiple (name, child_node) pairs to a directory node. Returns
+        a Deferred that fires (with None) when the operation finishes. This
+        is equivalent to calling set_node() multiple times, but is much more
+        efficient."""
+
+
     def add_file(name, uploadable):
         """I upload a file (using the given IUploadable), then attach the
         resulting FileNode to the directory at the given name. I return a
index fd270ce2c813816f0a7a06652581516965d7e892..fb0b3b105d8a6454bcd655bf38c69f75f00fc039 100644 (file)
@@ -606,6 +606,35 @@ class Web(WebMixin, unittest.TestCase):
 
         return d
 
+    def test_GET_DIRURL_large(self):
+        # Nevow has a problem showing more than about 192 children of a
+        # directory: it uses defer.success() and d.addCallback in a way that
+        # can make the stack grow very quickly. See ticket #237 for details.
+        # To work around this, I think we'll need to put a 'return
+        # defer.fireEventually' in our render_ method. This test is intended
+        # to trigger the bug (and eventually verify that our workaround
+        # actually works), but it isn't yet failing for me.
+
+        d = self.s.create_empty_dirnode()
+        COUNT = 400
+        def _created(dirnode):
+            entries = [ (str(i), self._foo_uri) for i in range(COUNT) ]
+            d2 = dirnode.set_uris(entries)
+            d2.addCallback(lambda res: dirnode)
+            return d2
+        d.addCallback(_created)
+
+        def _check(dirnode):
+            large_url = "/uri/" + dirnode.get_uri() + "/"
+            return self.GET(large_url)
+        d.addCallback(_check)
+
+        def _done(res):
+            self.failUnless('<a href="%d">%d</a>' % (COUNT-1, COUNT-1) in res)
+            self.failIf("maximum recursion depth exceeded" in res)
+        d.addCallback(_done)
+        return d
+
     def test_GET_DIRURL_json(self):
         d = self.GET(self.public_url + "/foo?t=json")
         d.addCallback(self.failUnlessIsFooJSON)