[Checkins] SVN: ZODB/trunk/src/ZODB/ Non-ghostifiable (persistent classes) objects load their state right

Jim Fulton jim at zope.com
Wed Jun 6 09:14:48 EDT 2007


Log message for revision 76408:
  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
  alreadey being loaded when necessary.
  

Changed:
  U   ZODB/trunk/src/ZODB/Connection.py
  U   ZODB/trunk/src/ZODB/tests/testpersistentclass.py

-=-
Modified: ZODB/trunk/src/ZODB/Connection.py
===================================================================
--- ZODB/trunk/src/ZODB/Connection.py	2007-06-06 13:14:40 UTC (rev 76407)
+++ ZODB/trunk/src/ZODB/Connection.py	2007-06-06 13:14:47 UTC (rev 76408)
@@ -105,6 +105,12 @@
         # recently used. Its API is roughly that of a dict, with
         # additional gc-related and invalidation-related methods.
         self._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
@@ -225,6 +231,9 @@
             return obj
         obj = self._added.get(oid, None)
         if obj is not None:
+            return obj        
+        obj = self._pre_cache.get(oid, None)
+        if obj is not None:
             return obj
 
         # This appears to be an MVCC violation because we are loading
@@ -233,11 +242,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/trunk/src/ZODB/tests/testpersistentclass.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testpersistentclass.py	2007-06-06 13:14:40 UTC (rev 76407)
+++ ZODB/trunk/src/ZODB/tests/testpersistentclass.py	2007-06-06 13:14:47 UTC (rev 76408)
@@ -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 Checkins mailing list