Commit 595ab70f authored by Tim Peters's avatar Tim Peters

Code and new test to ensure that making a savepoint triggers cache gc.

parent c0af1c8c
What's new in ZODB3 3.4.2a1?
============================
Release date: DD-MMM-2005
Following are dates of internal releases (to support ongoing Zope 2
development) since ZODB 3.4's last public release:
- 3.4.2a1 DD-MMM-2005
Savepoints
----------
- (3.4.2a1) As for deprecated subtransaction commits, the intent was
that making a savepoint would invoke incremental garbage collection on
Connection memory caches, to try to reduce the number of objects in
cache to the configured cache size. Due to an oversight, this didn't
happen, and stopped happening for subtransaction commits too. Making a
savepoint (or doing a subtransaction commit) does invoke cache gc now.
What's new in ZODB3 3.4.1? What's new in ZODB3 3.4.1?
========================== ==========================
Release date: 09-Aug-2005 Release date: 09-Aug-2005
...@@ -60,11 +80,15 @@ Subtransactions ...@@ -60,11 +80,15 @@ Subtransactions
to:: to::
transaction.savepoint() transaction.savepoint(True)
That is, make a savepoint, and forget it. As shown, it's best to pass
``True`` for the optional ``optimistic`` argument in this case: because
there's no possibility of asking for a rollback later, there's no need
to insist that all data managers support rollback.
That is, make a savepoint, and forget it. In rarer cases, a In rarer cases, a subtransaction commit is followed later by a
subtransaction commit is followed later by a subtransaction abort. In subtransaction abort. In that case, change the initial::
that case, change the initial::
transaction.commit(1) transaction.commit(1)
......
...@@ -1037,7 +1037,13 @@ class Connection(ExportImport, object): ...@@ -1037,7 +1037,13 @@ class Connection(ExportImport, object):
self._registered_objects = [] self._registered_objects = []
state = self._storage.position, self._storage.index.copy() state = self._storage.position, self._storage.index.copy()
return Savepoint(self, state) result = Savepoint(self, state)
# While the interface doesn't guarantee this, savepoints are
# sometimes used just to "break up" very long transactions, and as
# a pragmatic matter this is a good time to reduce the cache
# memory burden.
self.cacheGC()
return result
def _rollback(self, state): def _rollback(self, state):
self._abort() self._abort()
......
...@@ -70,6 +70,62 @@ savepoints.) ...@@ -70,6 +70,62 @@ savepoints.)
>>> transaction.commit() >>> transaction.commit()
""" """
def testSavepointDoesCacheGC():
"""\
Although the interface doesn't guarantee this internal detail, making a
savepoint should do incremental gc on connection memory caches. Indeed,
one traditional use for savepoints (started by the older, related
"subtransaction commit" idea) is simply to free memory space midstream
during a long transaction. Before ZODB 3.4.2, making a savepoint failed
to trigger cache gc, and this test verifies that it now does.
>>> import ZODB
>>> from ZODB.tests.MinPO import MinPO
>>> from ZODB.MappingStorage import MappingStorage
>>> import transaction
>>> CACHESIZE = 5 # something tiny
>>> LOOPCOUNT = CACHESIZE * 10
>>> st = MappingStorage("Test")
>>> db = ZODB.DB(st, cache_size=CACHESIZE)
>>> cn = db.open()
>>> rt = cn.root()
Now attach substantially more than CACHESIZE persistent objects to the root:
>>> for i in range(LOOPCOUNT):
... rt[i] = MinPO(i)
>>> transaction.commit()
Now modify all of them; the cache should contain LOOPCOUNT MinPO objects
then, + 1 for the root object:
>>> for i in range(LOOPCOUNT):
... obj = rt[i]
... obj.value = -i
>>> len(cn._cache) == LOOPCOUNT + 1
True
Making a savepoint at this time used to leave the cache holding the same
number of objects. Make sure the cache shrinks now instead.
>>> dummy = transaction.savepoint()
>>> len(cn._cache) <= CACHESIZE + 1
True
Verify all the values are as expected:
>>> failures = []
>>> for i in range(LOOPCOUNT):
... obj = rt[i]
... if obj.value != -i:
... failures.append(obj)
>>> failures
[]
>>> transaction.abort()
>>> db.close()
"""
def test_suite(): def test_suite():
return unittest.TestSuite(( return unittest.TestSuite((
doctest.DocFileSuite('testConnectionSavepoint.txt'), doctest.DocFileSuite('testConnectionSavepoint.txt'),
......
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