Index: src/ZODB/Connection.py =================================================================== --- src/ZODB/Connection.py (revision 103853) +++ src/ZODB/Connection.py (working copy) @@ -1139,8 +1139,9 @@ self._abort() self._registered_objects = [] src = self._storage - self._cache.invalidate(src.index) + index = src.index src.reset(*state) + self._cache.invalidate(index) def _commit_savepoint(self, transaction): """Commit all changes made in savepoints and begin 2-phase commit Index: src/ZODB/tests/testConnectionSavepoint.py =================================================================== --- src/ZODB/tests/testConnectionSavepoint.py (revision 103853) +++ src/ZODB/tests/testConnectionSavepoint.py (working copy) @@ -154,6 +154,34 @@ False """ +class SelfActivatingObject(persistent.Persistent): + + def _p_invalidate(self): + super(SelfActivatingObject, self)._p_invalidate() + self._p_activate() + +def testInvalidateAfterRollback(): + """\ +The rollback used to invalidate objects before resetting the TmpStore. +This caused problems for custom _p_invalidate methods that would load +the wrong state. + + >>> import ZODB.tests.util + >>> db = ZODB.tests.util.DB() + >>> connection = db.open() + >>> root = connection.root() + + >>> root['p'] = p = SelfActivatingObject() + >>> transaction.commit() + >>> p.foo = 1 + >>> sp = transaction.savepoint() + >>> p.foo = 2 + >>> sp2 = transaction.savepoint() + >>> sp.rollback() + >>> p.foo # This used to wrongly return 2 + 1 + """ + def tearDown(test): transaction.abort()