[Zodb-checkins] SVN: ZODB/branches/3.6/src/ZODB/ merged jim's fix (r76408) for the caching problem showing up in the zclasses tests:

Andreas Zeidler az at zitc.de
Thu Jun 28 09:19:37 EDT 2007


Log message for revision 77178:
  merged jim's fix (r76408) for the caching problem showing up in the zclasses tests:
    Non-ghostifiable (persistent classes) objects load their state right
    away -- even before they are placed in the cache.  This causes a
    problem if the object's state has a (direct or indirect) reference to
    it. Added a pre-cache that allows the connection to return objects
    already being loaded when necessary.

Changed:
  U   ZODB/branches/3.6/src/ZODB/Connection.py
  U   ZODB/branches/3.6/src/ZODB/tests/testpersistentclass.py

-=-
Modified: ZODB/branches/3.6/src/ZODB/Connection.py
===================================================================
--- ZODB/branches/3.6/src/ZODB/Connection.py	2007-06-28 12:35:43 UTC (rev 77177)
+++ ZODB/branches/3.6/src/ZODB/Connection.py	2007-06-28 13:19:37 UTC (rev 77178)
@@ -88,6 +88,12 @@
 
         self._version = version
         self._cache = cache = PickleCache(self, cache_size)
+
+        # The pre-cache is used by get to avoid infinite loops when
+        # objects immediately load their state whern they get their
+        # persistent data set.
+        self._pre_cache = {}
+        
         if version:
             # Caches for versions end up empty if the version
             # is not used for a while. Non-version caches
@@ -191,6 +197,9 @@
         if self._opened is None:
             raise ConnectionStateError("The database connection is closed")
 
+        obj = self._pre_cache.get(oid, None)
+        if obj is not None:
+            return obj
         obj = self._cache.get(oid, None)
         if obj is not None:
             return obj
@@ -201,11 +210,14 @@
         p, serial = self._storage.load(oid, self._version)
         obj = self._reader.getGhost(p)
 
+        # Avoid infiniate loop if obj tries to load its state before
+        # it is added to the cache and it's state refers to it.
+        self._pre_cache[oid] = obj
         obj._p_oid = oid
         obj._p_jar = self
         obj._p_changed = None
         obj._p_serial = serial
-
+        self._pre_cache.pop(oid)
         self._cache[oid] = obj
         return obj
 

Modified: ZODB/branches/3.6/src/ZODB/tests/testpersistentclass.py
===================================================================
--- ZODB/branches/3.6/src/ZODB/tests/testpersistentclass.py	2007-06-28 12:35:43 UTC (rev 77177)
+++ ZODB/branches/3.6/src/ZODB/tests/testpersistentclass.py	2007-06-28 13:19:37 UTC (rev 77178)
@@ -21,8 +21,29 @@
 import ZODB.tests.util
 import transaction
 from zope.testing import doctest
+import ZODB.persistentclass
 
+def class_with_circular_ref_to_self():
+    """
+It should be possible for a class to reger to itself.
 
+    >>> class C:
+    ...     __metaclass__ = ZODB.persistentclass.PersistentMetaClass
+
+    >>> C.me = C
+    >>> db = ZODB.tests.util.DB()
+    >>> conn = db.open()
+    >>> conn.root()['C'] = C
+    >>> transaction.commit()
+
+    >>> conn2 = db.open()
+    >>> C2 = conn2.root()['C']
+    >>> c = C2()
+    >>> c.__class__.__name__
+    'C'
+    
+"""
+
 # XXX need to update files to get newer testing package
 class FakeModule:
     def __init__(self, name, dict):
@@ -44,6 +65,7 @@
     return unittest.TestSuite((
         doctest.DocFileSuite("../persistentclass.txt",
                              setUp=setUp, tearDown=tearDown),
+        doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
         ))
 
 if __name__ == '__main__':



More information about the Zodb-checkins mailing list