Commit 06a592db authored by Andreas Zeidler's avatar Andreas Zeidler

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.
parent 553ed8bc
......@@ -88,6 +88,12 @@ class Connection(ExportImport, object):
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 @@ class Connection(ExportImport, object):
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 @@ class Connection(ExportImport, object):
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
......
......@@ -21,7 +21,28 @@ import unittest
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:
......@@ -44,6 +65,7 @@ def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite("../persistentclass.txt",
setUp=setUp, tearDown=tearDown),
doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
))
if __name__ == '__main__':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment