Commit d818fbd3 authored by Christian Theune's avatar Christian Theune

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.)
parent 13b1f7e3
...@@ -62,6 +62,10 @@ Connection management ...@@ -62,6 +62,10 @@ Connection management
and/or store limited resources (such as RDB connections) in connection and/or store limited resources (such as RDB connections) in connection
caches may benefit. caches may benefit.
- (3.7.0c1) 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.)
DemoStorage DemoStorage
----------- -----------
......
...@@ -145,9 +145,17 @@ class _ConnectionPool(object): ...@@ -145,9 +145,17 @@ class _ConnectionPool(object):
assert result in self.all assert result in self.all
return result return result
# For every live connection c, invoke f(c). def map(self, f, open_connections=True):
def map(self, f): """For every live connection c, invoke f(c).
self.all.map(f)
If `open_connections` is false then only call f(c) on closed
connections.
"""
if open_connections:
self.all.map(f)
else:
map(f, self.available)
class DB(object): class DB(object):
"""The Object Database """The Object Database
...@@ -304,12 +312,17 @@ class DB(object): ...@@ -304,12 +312,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()
...@@ -548,7 +561,7 @@ class DB(object): ...@@ -548,7 +561,7 @@ class DB(object):
result.open(transaction_manager, mvcc, synch) result.open(transaction_manager, mvcc, synch)
# 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