Commit d5cfadcb authored by Jim Fulton's avatar Jim Fulton

Bug Fixed

  When a transaction rolled back a savepoint after adding objects and
  subsequently added more objects and committed, an error could be
  raised "ValueError: A different object already has the same oid"
  causing the transaction to fail. Worse, this could leave a database
  in a state where subsequent transactions in the same process would
  fail.

https://bugs.launchpad.net/zodb/+bug/665452
parent d2c13694
...@@ -2,6 +2,21 @@ ...@@ -2,6 +2,21 @@
Change History Change History
================ ================
3.10.1 (2010-10-??)
===================
Bugs Fixed
----------
- When a transaction rolled back a savepoint after adding objects and
subsequently added more objects and committed, an error could be
raised "ValueError: A different object already has the same oid"
causing the transaction to fail. Worse, this could leave a database
in a state where subsequent transactions in the same process would
fail.
https://bugs.launchpad.net/zodb/+bug/665452
3.10.0 (2010-10-08) 3.10.0 (2010-10-08)
=================== ===================
......
...@@ -757,6 +757,7 @@ class Connection(ExportImport, object): ...@@ -757,6 +757,7 @@ class Connection(ExportImport, object):
"""Disown any objects newly saved in an uncommitted transaction.""" """Disown any objects newly saved in an uncommitted transaction."""
if creating is None: if creating is None:
creating = self._creating creating = self._creating
self._creating = {}
for oid in creating: for oid in creating:
self._db.save_oid(oid) self._db.save_oid(oid)
...@@ -768,7 +769,6 @@ class Connection(ExportImport, object): ...@@ -768,7 +769,6 @@ class Connection(ExportImport, object):
del o._p_jar del o._p_jar
del o._p_oid del o._p_oid
creating.clear()
def tpc_vote(self, transaction): def tpc_vote(self, transaction):
"""Verify that a data manager can commit the transaction.""" """Verify that a data manager can commit the transaction."""
...@@ -1140,7 +1140,10 @@ class Connection(ExportImport, object): ...@@ -1140,7 +1140,10 @@ class Connection(ExportImport, object):
self._abort() self._abort()
self._registered_objects = [] self._registered_objects = []
src = self._storage src = self._storage
self._invalidate_creating(src.creating)
# Invalidate objects created *after* the savepoint.
self._invalidate_creating((oid for oid in src.creating
if oid not in state[2]))
index = src.index index = src.index
src.reset(*state) src.reset(*state)
self._cache.invalidate(index) self._cache.invalidate(index)
......
...@@ -230,6 +230,40 @@ def testNewOidsGetReusedOnRollback(): ...@@ -230,6 +230,40 @@ def testNewOidsGetReusedOnRollback():
>>> transaction.abort() >>> transaction.abort()
""" """
def testNewOidNotReusedAfterRollbackOfPostAddSavepoint():
"""\
>>> connection = ZODB.connection(None)
>>> root = connection.root()
Add an item, and make a savepoint.
>>> root['p'] = p = ZODB.tests.util.P()
>>> sp = transaction.savepoint()
Now rollback the savepoint.
>>> sp.rollback()
At this point, the item still exists, since it was created before
the savepoint we rolled back.
>>> root['p']._p_oid
'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01'
Add another item, and make another savepoint.
>>> root['p2'] = p2 = ZODB.tests.util.P()
>>> sp2 = transaction.savepoint()
The second item should not reuse the oid of the first.
>>> p2._p_oid
'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02'
transaction.abort()
"""
def tearDown(test): def tearDown(test):
transaction.abort() transaction.abort()
......
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