Commit 76a6eef2 authored by Vincent Pelletier's avatar Vincent Pelletier

Ignore TID chronology when detecting & resolving conflicts.

If TID allocation and conflict resolution are serialised at database scope
(=cluster scope in NEO), the question doesn't arises: when we have a TID,
we are the latest TID until we call tpc_finish.
If they are not serialised, it means TID allocation will happen after
conflict resolution, as TID generation must be serialised anyway, and in
such case, the temporary TID we have when detecting conflicts has no
ordering signification, so it is meaningless to check their chronology.

git-svn-id: https://svn.erp5.org/repos/neo/trunk@2533 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent 4e402dda
...@@ -816,28 +816,23 @@ class Application(object): ...@@ -816,28 +816,23 @@ class Application(object):
tid = local_var.tid tid = local_var.tid
resolved = False resolved = False
if data is not None: if data is not None:
if conflict_serial <= tid: new_data = tryToResolveConflict(oid, conflict_serial,
new_data = tryToResolveConflict(oid, conflict_serial, serial, data)
serial, data) if new_data is not None:
if new_data is not None: neo.logging.info('Conflict resolution succeed for ' \
neo.logging.info('Conflict resolution succeed for ' \ '%r:%r with %r', dump(oid), dump(serial),
'%r:%r with %r', dump(oid), dump(serial), dump(conflict_serial))
dump(conflict_serial)) # Mark this conflict as resolved
# Mark this conflict as resolved resolved_serial_set.update(conflict_serial_dict.pop(
resolved_serial_set.update(conflict_serial_dict.pop( oid))
oid)) # Try to store again
# Try to store again self._store(oid, conflict_serial, new_data)
self._store(oid, conflict_serial, new_data) append(oid)
append(oid) resolved = True
resolved = True
else:
neo.logging.info('Conflict resolution failed for ' \
'%r:%r with %r', dump(oid), dump(serial),
dump(conflict_serial))
else: else:
neo.logging.info('Conflict reported for %r:%r with ' \ neo.logging.info('Conflict resolution failed for ' \
'later transaction %r , cannot resolve conflict.', '%r:%r with %r', dump(oid), dump(serial),
dump(oid), dump(serial), dump(conflict_serial)) dump(conflict_serial))
if not resolved: if not resolved:
# XXX: Is it really required to remove from data_dict ? # XXX: Is it really required to remove from data_dict ?
del data_dict[oid] del data_dict[oid]
......
...@@ -220,17 +220,11 @@ class TransactionManager(object): ...@@ -220,17 +220,11 @@ class TransactionManager(object):
raise ConflictError(history_list[0][0]) raise ConflictError(history_list[0][0])
neo.logging.info('Transaction %s storing %s', dump(tid), dump(oid)) neo.logging.info('Transaction %s storing %s', dump(tid), dump(oid))
self._store_lock_dict[oid] = tid self._store_lock_dict[oid] = tid
elif locking_tid < tid: else:
# a previous transaction lock this object, retry later # a previous transaction lock this object, retry later
neo.logging.info('Store delayed for %r:%r by %r', dump(oid), neo.logging.info('Store delayed for %r:%r by %r', dump(oid),
dump(tid), dump(locking_tid)) dump(tid), dump(locking_tid))
raise DelayedError raise DelayedError
else:
# If a newer transaction already locks this object,
# do not try to resolve a conflict, so return immediately.
neo.logging.info('Unresolvable conflict on %r:%r with %r',
dump(oid), dump(tid), dump(locking_tid))
raise ConflictError(locking_tid)
def checkCurrentSerial(self, tid, serial, oid): def checkCurrentSerial(self, tid, serial, oid):
self.lockObject(tid, serial, oid) self.lockObject(tid, serial, oid)
......
...@@ -155,26 +155,6 @@ class TransactionManagerTests(NeoUnitTestBase): ...@@ -155,26 +155,6 @@ class TransactionManagerTests(NeoUnitTestBase):
self.assertRaises(DelayedError, self.manager.storeObject, self.assertRaises(DelayedError, self.manager.storeObject,
tid2, serial, *obj) tid2, serial, *obj)
def testUnresolvableConflict(self):
""" A newer transaction has already modified an object """
uuid = self.getNewUUID()
tid1, txn1 = self._getTransaction()
tid2, txn2 = self._getTransaction()
serial, obj = self._getObject(1)
# the (later) transaction lock (change) the object
self.manager.register(uuid, tid2)
self.manager.storeTransaction(tid2, *txn2)
self.manager.storeObject(tid2, serial, *obj)
self.assertTrue(tid2 in self.manager)
self._storeTransactionObjects(tid2, txn2)
self.manager.lock(tid2, txn2[0])
# the previous it's not using the latest version
self.manager.register(uuid, tid1)
self.manager.storeTransaction(tid1, *txn1)
self.assertTrue(tid1 in self.manager)
self.assertRaises(ConflictError, self.manager.storeObject,
tid1, serial, *obj)
def testResolvableConflict(self): def testResolvableConflict(self):
""" Try to store an object with the lastest revision """ """ Try to store an object with the lastest revision """
uuid = self.getNewUUID() uuid = self.getNewUUID()
...@@ -229,13 +209,13 @@ class TransactionManagerTests(NeoUnitTestBase): ...@@ -229,13 +209,13 @@ class TransactionManagerTests(NeoUnitTestBase):
self.manager.storeObject(tid2, serial2, *obj2) self.manager.storeObject(tid2, serial2, *obj2)
self.assertTrue(tid2 in self.manager) self.assertTrue(tid2 in self.manager)
self.manager.lock(tid2, txn1[0]) self.manager.lock(tid2, txn1[0])
# the first get a conflict # the first get a delay, as nothing is committed yet
self.manager.register(uuid1, tid1) self.manager.register(uuid1, tid1)
self.manager.storeTransaction(tid1, *txn1) self.manager.storeTransaction(tid1, *txn1)
self.assertTrue(tid1 in self.manager) self.assertTrue(tid1 in self.manager)
self.assertRaises(ConflictError, self.manager.storeObject, self.assertRaises(DelayedError, self.manager.storeObject,
tid1, serial1, *obj1) tid1, serial1, *obj1)
self.assertRaises(ConflictError, self.manager.storeObject, self.assertRaises(DelayedError, self.manager.storeObject,
tid1, serial2, *obj2) tid1, serial2, *obj2)
def testAbortUnlocked(self): def testAbortUnlocked(self):
......
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