Commit c486c7f9 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 d818fbd3
...@@ -88,6 +88,12 @@ class Connection(ExportImport, object): ...@@ -88,6 +88,12 @@ class Connection(ExportImport, object):
self._version = version self._version = version
self._cache = cache = PickleCache(self, cache_size) 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: if version:
# Caches for versions end up empty if the version # Caches for versions end up empty if the version
# is not used for a while. Non-version caches # is not used for a while. Non-version caches
...@@ -198,17 +204,23 @@ class Connection(ExportImport, object): ...@@ -198,17 +204,23 @@ class Connection(ExportImport, object):
if obj is not None: if obj is not None:
return obj return obj
obj = self._added.get(oid, None) 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: if obj is not None:
return obj return obj
p, serial = self._storage.load(oid, self._version) p, serial = self._storage.load(oid, self._version)
obj = self._reader.getGhost(p) 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_oid = oid
obj._p_jar = self obj._p_jar = self
obj._p_changed = None obj._p_changed = None
obj._p_serial = serial obj._p_serial = serial
self._pre_cache.pop(oid)
self._cache[oid] = obj self._cache[oid] = obj
return obj return obj
......
...@@ -21,7 +21,28 @@ import unittest ...@@ -21,7 +21,28 @@ import unittest
import ZODB.tests.util import ZODB.tests.util
import transaction import transaction
from zope.testing import doctest 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 # XXX need to update files to get newer testing package
class FakeModule: class FakeModule:
...@@ -44,6 +65,7 @@ def test_suite(): ...@@ -44,6 +65,7 @@ def test_suite():
return unittest.TestSuite(( return unittest.TestSuite((
doctest.DocFileSuite("../persistentclass.txt", doctest.DocFileSuite("../persistentclass.txt",
setUp=setUp, tearDown=tearDown), setUp=setUp, tearDown=tearDown),
doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
)) ))
if __name__ == '__main__': 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