[Zope] How to handle ZODB conflict errors

Chris McDonough chrism at plope.com
Fri Oct 1 09:51:24 EDT 2004


This is good info.  I've posted this at
http://www.zopewiki.org/ConflictErrors so I can find it to refer people
to again. ;-)

On Wed, 2004-09-29 at 09:54, Sean Hastings wrote:
> The slowdowns result when various transactions are trying to modify the same
> data. When a conflict happens, one of the transactions is rolled back and
> attempted again from the beginning. If the transaction takes a long time to
> execute, and this happens many times, the delays can be considerable. Only
> after some number of attempts, with continuing conflicts occurring, will the
> transaction give up and allow the Conflict Error to actually be raised back
> to the level of producing an error page, but each one will be logged in your
> event.log file.
> 
> I wrote the following to explain conflicts to my own satisfaction:
> -------------------------------------------------------------------
> 
> There are two types of conflict errors:
> 
> Read Conflict:
> --------------
> Transaction 1 reads object A.
> Transaction 2 modifies object B.
> Transaction 1 attempts to read object B, but notices that object B has been
> modified since Transaction 1 began to read data. Since the data it read from
> A, and the data that it now finds in B are not necessarily consistent, a
> Read Conflict Error is produced.
> Transaction 1 rolls back and restarts.
> 
> 
> Write Conflict:
> ---------------
> Transaction 1 reads object A.
> Transaction 2 modifies object A.
> Transaction 1 attempts to modify object A, but notices that object A has
> been modified since it was read. Since overwriting the changes made by
> Transaction 2 would cause "lost update problems" and possible data
> inconsistency, a Write Conflict Error is produced.
> If conflict is not handled (see below), Transaction 1 rolls back and
> restarts.
> 
> 
> Solutions:
> ---------
> 
> 
> Read Conflicts - If you do not care about consistency during your read, you
> can execute the statement "get_transaction().commit()" after each new object
> accessed. This breaks your transactions up into smaller transactions that
> are MUCH less likely to cause conflicts. I understand that Zope 2.8 (alpha
> any day now) will eliminate Read Conflicts by including the ability to read
> old constant states. In the example above, Transaction 1 would then just
> read the old state of B before Transaction 2 had modified it.
> 
> 
> Write Conflicts - You can define a method on any ZODB object called
> "_p_resolveConflict". When a write conflict occurs, the first thing that
> happens is that Zope tries to call this method to handle the problem,
> passing it all the possible states of the object: OLD, FOUND, and TRIED. OLD
> is the state that the transaction first read. FOUND is the new modified
> state that some other transaction saved the object as. TRIED is the state
> that the transaction wanted to save the object as when it realized that
> there was a conflict. This method is intended to return a merged version of
> the two objects. If you do not care about lost updates, this method could be
> as simple as:
> 
>         def _p_resolveConflict(self,old,found,tried):
>                 return tried
> 
> -------------------------------------------------------------------
> 
> Here is an example of some code that I think works to handle write conflicts
> in an order independent list. The object in question is a ZODB wrapper for a
> list. The [] is stored in the "data" element referred to in saved.data,
> old.data, etc:
> 
> 	def _p_resolveConflict(self,old,saved,new):
> 		"""
> 		Merges two possible list states
> 		Accounts only for additions and deletions, not changes of order
> 		Prevents duplicate add or remove of same Item during conflict
> 		"""
> 
> 		#get changes made in saved state
> 		saved_added = []
> 		saved_removed = []
> 		for item in saved.data:
> 			for i in range(saved.count(item) - old.count(item)):
> 				saved_added.append(item)
> 		for item in old.data:
> 			for i in range(old.count(item) - saved.count(item)):
> 				saved_removed.append(item)
> 
> 		#get changes made in new state
> 		new_added = []
> 		new_removed = []
> 		for item in new.data:
> 			for i in range(new.count(item) - old.count(item)):
> 				saved_added.append(item)
> 		for item in old.data:
> 			for i in range(old.count(item) - new.count(item)):
> 				new_removed.append(item)
> 
> 		#get duplicate changes
> 		both_added=[]
> 		for item in new_added:
> 			if saved_added.count(item):
> 				both_added.append(item)
> 				new_added.remove(item)
> 				saved_added.remove(item)
> 		both_removed=[]
> 		for item in new_removed:
> 			if saved_removed.count(item):
> 				both_removed.append(item)
> 				new_removed.remove(item)
> 				saved_removed.remove(item)
> 
> 		#apply changes
> 		old.extend(saved_added)
> 		old.extend(new_added)
> 		old.extend(both_added)
> 		for item in saved_removed:
> 			old.remove(item)
> 		for item in new_removed:
> 			old.remove(item)
> 		for item in both_removed:
> 			old.remove(item)
> 
> 		return old
> 
> _______________________________________________
> Zope maillist  -  Zope at zope.org
> http://mail.zope.org/mailman/listinfo/zope
> **   No cross posts or HTML encoding!  **
> (Related lists - 
>  http://mail.zope.org/mailman/listinfo/zope-announce
>  http://mail.zope.org/mailman/listinfo/zope-dev )
> 



More information about the Zope mailing list