From 26187bfc8166a868b77cb4f65301cc3ba29f786a Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Thu, 8 May 2008 18:02:55 -0700
Subject: [PATCH] use a weakref cache in the client to manage singleton
 filenodes/dirnodes, to avoid autocollision. Should close #391.

---
 src/allmydata/client.py           | 30 ++++++++++++++++++------------
 src/allmydata/test/test_system.py |  2 ++
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/src/allmydata/client.py b/src/allmydata/client.py
index 95cd8ff7..82c97735 100644
--- a/src/allmydata/client.py
+++ b/src/allmydata/client.py
@@ -1,5 +1,5 @@
 
-import os, stat, time, re
+import os, stat, time, re, weakref
 from allmydata.interfaces import RIStorageServer
 from allmydata import node
 
@@ -170,6 +170,7 @@ class Client(node.Node, testutil.PollMixin):
         helper_furl = self.get_config("helper.furl")
         convergence_s = self.get_or_create_private_config('convergence', _make_secret)
         self.convergence = base32.a2b(convergence_s)
+        self._node_cache = weakref.WeakValueDictionary() # uri -> node
         self.add_service(Uploader(helper_furl, self.stats_provider))
         self.add_service(Downloader(self.stats_provider))
         self.add_service(Checker())
@@ -292,17 +293,22 @@ class Client(node.Node, testutil.PollMixin):
     def create_node_from_uri(self, u):
         # this returns synchronously.
         u = IURI(u)
-        if IReadonlyNewDirectoryURI.providedBy(u):
-            # new-style read-only dirnodes
-            return NewDirectoryNode(self).init_from_uri(u)
-        if INewDirectoryURI.providedBy(u):
-            # new-style dirnodes
-            return NewDirectoryNode(self).init_from_uri(u)
-        if IFileURI.providedBy(u):
-            # CHK
-            return FileNode(u, self)
-        assert IMutableFileURI.providedBy(u), u
-        return MutableFileNode(self).init_from_uri(u)
+        u_s = u.to_string()
+        if u_s not in self._node_cache:
+            if IReadonlyNewDirectoryURI.providedBy(u):
+                # new-style read-only dirnodes
+                node = NewDirectoryNode(self).init_from_uri(u)
+            elif INewDirectoryURI.providedBy(u):
+                # new-style dirnodes
+                node = NewDirectoryNode(self).init_from_uri(u)
+            elif IFileURI.providedBy(u):
+                # CHK
+                node = FileNode(u, self)
+            else:
+                assert IMutableFileURI.providedBy(u), u
+                node = MutableFileNode(self).init_from_uri(u)
+            self._node_cache[u_s] = node
+        return self._node_cache[u_s]
 
     def notify_publish(self, publish_status, size):
         self.getServiceNamed("mutable-watcher").notify_publish(publish_status,
diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
index 60aa97d6..5dad8bb7 100644
--- a/src/allmydata/test/test_system.py
+++ b/src/allmydata/test/test_system.py
@@ -702,6 +702,8 @@ class SystemTest(testutil.SignalMixin, testutil.PollMixin, testutil.StallMixin,
             uri = self._mutable_node_1.get_uri()
             log.msg("starting retrieve1")
             newnode = self.clients[0].create_node_from_uri(uri)
+            newnode_2 = self.clients[0].create_node_from_uri(uri)
+            self.failUnlessIdentical(newnode, newnode_2)
             return newnode.download_best_version()
         d.addCallback(_check_download_1)
 
-- 
2.45.2