Commit f3841bd1 authored by Christian Theune's avatar Christian Theune

- Fixed bug 113932 by changing automatic garbage collection to only work on

   closed connections.
parent b36489aa
...@@ -10,6 +10,10 @@ General ...@@ -10,6 +10,10 @@ General
will be removed in ZODB 3.9. (They have been widely recognized as will be removed in ZODB 3.9. (They have been widely recognized as
deprecated for quite a while.) deprecated for quite a while.)
- Changed the automatic garbage collection when opening a connection to only
apply the garbage collections on those connections in the pool that are
closed. (This fixed issue 113932.)
ZEO ZEO
--- ---
......
...@@ -160,9 +160,17 @@ class _ConnectionPool(object): ...@@ -160,9 +160,17 @@ class _ConnectionPool(object):
assert result in self.all assert result in self.all
return result return result
def map(self, f): def map(self, f, open_connections=True):
"""For every live connection c, invoke f(c).""" """For every live connection c, invoke f(c).
If `open_connections` is false then only call f(c) on closed
connections.
"""
if open_connections:
self.all.map(f) self.all.map(f)
else:
map(f, self.available)
class DB(object): class DB(object):
"""The Object Database """The Object Database
...@@ -360,12 +368,17 @@ class DB(object): ...@@ -360,12 +368,17 @@ class DB(object):
finally: finally:
self._r() self._r()
# Call f(c) for all connections c in all pools in all versions. def _connectionMap(self, f, open_connections=True):
def _connectionMap(self, f): """Call f(c) for all connections c in all pools in all versions.
If `open_connections` is false then f(c) is only called on closed
connections.
"""
self._a() self._a()
try: try:
for pool in self._pools.values(): for pool in self._pools.values():
pool.map(f) pool.map(f, open_connections=open_connections)
finally: finally:
self._r() self._r()
...@@ -608,7 +621,7 @@ class DB(object): ...@@ -608,7 +621,7 @@ class DB(object):
result.open(transaction_manager) result.open(transaction_manager)
# A good time to do some cache cleanup. # A good time to do some cache cleanup.
self._connectionMap(lambda c: c.cacheGC()) self._connectionMap(lambda c: c.cacheGC(), open_connections=False)
return result return result
......
...@@ -51,6 +51,9 @@ class RegularObject(Persistent): ...@@ -51,6 +51,9 @@ class RegularObject(Persistent):
init = classmethod(init) init = classmethod(init)
class PersistentObject(Persistent):
pass
class CacheTests: class CacheTests:
def test_cache(self): def test_cache(self):
...@@ -204,6 +207,35 @@ class CacheTests: ...@@ -204,6 +207,35 @@ class CacheTests:
4 4
""" """
def test_gc_on_open_connections(self):
r"""Test that automatic GC is not applied to open connections.
This test (and the corresponding fix) was introduced because of bug
report 113923.
We start with a persistent object and add a list attribute::
>>> db = databaseFromString("<zodb>\n"
... "cache-size 0\n"
... "<mappingstorage/>\n"
... "</zodb>")
>>> cn1 = db.open()
>>> r = cn1.root()
>>> r['ob'] = PersistentObject()
>>> r['ob'].l = []
>>> transaction.commit()
Now, let's modify the object in a way that doesn't get noticed. Then,
we open another connection which triggers automatic garbage
connection. After that, the object should not have been ghostified::
>>> r['ob'].l.append(1)
>>> cn2 = db.open()
>>> r['ob'].l
[1]
"""
def test_suite(): def test_suite():
return doctest.DocTestSuite() return doctest.DocTestSuite()
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