Commit c7b7c0ee authored by Jim Fulton's avatar Jim Fulton

Bug Fixed

- Updating blobs in save points could cause spurious "invalidations
  out of order" errors.  https://bugs.launchpad.net/zodb/+bug/509801

(Thanks to Christian Zagrodnick for chasing this down.)
parent ae1636e9
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
Bugs Fixed Bugs Fixed
---------- ----------
- Updating blobs in save points could cause spurious "invalidations
out of order" errors. https://bugs.launchpad.net/zodb/+bug/509801
(Thanks to Christian Zagrodnick for chasing this down.)
- On Mac OS X, clients that connected and disconnected quickly could - On Mac OS X, clients that connected and disconnected quickly could
cause a ZEO server to stop accepting connections, due to a failure cause a ZEO server to stop accepting connections, due to a failure
to catch errors in the initial part of the connection process. to catch errors in the initial part of the connection process.
......
...@@ -335,13 +335,13 @@ class Connection(ExportImport, object): ...@@ -335,13 +335,13 @@ class Connection(ExportImport, object):
def invalidate(self, tid, oids): def invalidate(self, tid, oids):
"""Notify the Connection that transaction 'tid' invalidated oids.""" """Notify the Connection that transaction 'tid' invalidated oids."""
if self.before is not None: if self.before is not None:
# this is an historical connection. Invalidations are irrelevant. # This is a historical connection. Invalidations are irrelevant.
return return
self._inv_lock.acquire() self._inv_lock.acquire()
try: try:
if self._txn_time is None: if self._txn_time is None:
self._txn_time = tid self._txn_time = tid
elif tid < self._txn_time: elif (tid < self._txn_time) and (tid is not None):
raise AssertionError("invalidations out of order, %r < %r" raise AssertionError("invalidations out of order, %r < %r"
% (tid, self._txn_time)) % (tid, self._txn_time))
...@@ -1175,7 +1175,7 @@ class Connection(ExportImport, object): ...@@ -1175,7 +1175,7 @@ class Connection(ExportImport, object):
# that that the next attribute access of its name # that that the next attribute access of its name
# unghostify it, which will cause its blob data # unghostify it, which will cause its blob data
# to be reattached "cleanly" # to be reattached "cleanly"
self.invalidate(s, {oid:True}) self.invalidate(None, (oid, ))
else: else:
s = self._storage.store(oid, serial, data, s = self._storage.store(oid, serial, data,
'', transaction) '', transaction)
......
...@@ -563,6 +563,35 @@ def savepoint_isolation(): ...@@ -563,6 +563,35 @@ def savepoint_isolation():
>>> db.close() >>> db.close()
""" """
def savepoint_commits_without_invalidations_out_of_order():
"""Make sure transactions with blobs can be commited without the
invalidations out of order error (LP #509801)
>>> bs = create_storage()
>>> db = DB(bs)
>>> tm1 = transaction.TransactionManager()
>>> conn1 = db.open(transaction_manager=tm1)
>>> conn1.root.b = ZODB.blob.Blob('initial')
>>> tm1.commit()
>>> conn1.root.b.open('w').write('1')
>>> _ = tm1.savepoint()
>>> tm2 = transaction.TransactionManager()
>>> conn2 = db.open(transaction_manager=tm2)
>>> conn2.root.b.open('w').write('2')
>>> _ = tm1.savepoint()
>>> conn1.root.b.open().read()
'1'
>>> conn2.root.b.open().read()
'2'
>>> tm2.commit()
>>> tm1.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ConflictError: database conflict error...
>>> db.close()
"""
def savepoint_cleanup(): def savepoint_cleanup():
"""Make sure savepoint data gets cleaned up. """Make sure savepoint data gets cleaned up.
......
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