#1382705 forbid with sql level locking the simultaneous fireing of a transition on a given entity stable
authorAlexandre Fayolle <alexandre.fayolle@logilab.fr>
Tue, 21 Dec 2010 21:20:19 +0100
branchstable
changeset 6757 bc878ec35794
parent 6756 46297c498842
child 6758 28b11ecf319b
#1382705 forbid with sql level locking the simultaneous fireing of a transition on a given entity
hooks/workflow.py
misc/migration/3.10.7_Any.py
schemas/workflow.py
--- a/hooks/workflow.py	Mon Jan 03 11:22:32 2011 +0100
+++ b/hooks/workflow.py	Tue Dec 21 21:20:19 2010 +0100
@@ -191,6 +191,8 @@
             msg = session._('mandatory relation')
             raise ValidationError(entity.eid, {qname: msg})
         forentity = session.entity_from_eid(foreid)
+        # see comment in the TrInfo entity definition
+        entity.cw_edited['tr_count']=len(forentity.reverse_wf_info_for)
         iworkflowable = forentity.cw_adapt_to('IWorkflowable')
         # then check it has a workflow set, unless we're in the process of changing
         # entity's workflow
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.10.7_Any.py	Tue Dec 21 21:20:19 2010 +0100
@@ -0,0 +1,2 @@
+add_attribute('TrInfo', 'tr_count')
+sync_schema_props_perms('TrInfo')
--- a/schemas/workflow.py	Mon Jan 03 11:22:32 2011 +0100
+++ b/schemas/workflow.py	Tue Dec 21 21:20:19 2010 +0100
@@ -22,7 +22,7 @@
 _ = unicode
 
 from yams.buildobjs import (EntityType, RelationType, SubjectRelation,
-                            RichString, String)
+                            RichString, String, Int)
 from cubicweb.schema import RQLConstraint, RQLUniqueConstraint
 from cubicweb.schemas import (META_ETYPE_PERMS, META_RTYPE_PERMS,
                               HOOKS_RTYPE_PERMS)
@@ -159,13 +159,21 @@
         'delete': (), # XXX should we allow managers to delete TrInfo?
         'update': ('managers', 'owners',),
     }
-
-    from_state = SubjectRelation('State', cardinality='1*')
-    to_state = SubjectRelation('State', cardinality='1*')
+    # The unique_together constraint ensures that 2 repositories
+    # sharing the db won't be able to fire a transition simultaneously
+    # on the same entity tr_count is filled in the FireTransitionHook
+    # to the number of TrInfo attached to the entity on which we
+    # attempt to fire a transition. In other word, it contains the
+    # rank of the TrInfo for that entity, and the constraint says we
+    # cannot have 2 TrInfo with the same rank.
+    __unique_together__ = [('tr_count', 'wf_info_for')]
+    from_state = SubjectRelation('State', cardinality='1*', inlined=True)
+    to_state = SubjectRelation('State', cardinality='1*', inlined=True)
     # make by_transition optional because we want to allow managers to set
     # entity into an arbitrary state without having to respect wf transition
     by_transition = SubjectRelation('BaseTransition', cardinality='?*')
     comment = RichString(fulltextindexed=True)
+    tr_count = Int(description='autocomputed attribute used to ensure transition coherency')
     # get actor and date time using owned_by and creation_date
 
 class from_state(RelationType):