server/hooks.py
branchstable
changeset 4502 1422589c35a0
parent 4489 63128e8b9af9
child 4496 14cbf2570ce8
equal deleted inserted replaced
4501:71ba2d0f34f2 4502:1422589c35a0
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     8 """
     8 """
     9 __docformat__ = "restructuredtext en"
     9 __docformat__ = "restructuredtext en"
    10 
    10 
       
    11 from threading import Lock
    11 from datetime import datetime
    12 from datetime import datetime
    12 
    13 
    13 from cubicweb import UnknownProperty, ValidationError, BadConnectionId
    14 from cubicweb import UnknownProperty, ValidationError, BadConnectionId
    14 from cubicweb.schema import RQLConstraint, RQLUniqueConstraint
    15 from cubicweb.schema import RQLConstraint, RQLUniqueConstraint
    15 from cubicweb.server.pool import Operation, LateOperation, PreCommitOperation
    16 from cubicweb.server.pool import Operation, LateOperation, PreCommitOperation
    22 DONT_CHECK_RTYPES_ON_ADD = set(('owned_by', 'created_by',
    23 DONT_CHECK_RTYPES_ON_ADD = set(('owned_by', 'created_by',
    23                                 'is', 'is_instance_of',
    24                                 'is', 'is_instance_of',
    24                                 'wf_info_for', 'from_state', 'to_state'))
    25                                 'wf_info_for', 'from_state', 'to_state'))
    25 DONT_CHECK_RTYPES_ON_DEL = set(('is', 'is_instance_of',
    26 DONT_CHECK_RTYPES_ON_DEL = set(('is', 'is_instance_of',
    26                                 'wf_info_for', 'from_state', 'to_state'))
    27                                 'wf_info_for', 'from_state', 'to_state'))
       
    28 
       
    29 _UNIQUE_CONSTRAINTS_LOCK = Lock()
       
    30 _UNIQUE_CONSTRAINTS_HOLDER = None
       
    31 
       
    32 class _ReleaseUniqueConstraintsHook(Operation):
       
    33     def commit_event(self):
       
    34         pass
       
    35     def postcommit_event(self):
       
    36         _release_unique_cstr_lock(self.session)
       
    37     def rollback_event(self):
       
    38         _release_unique_cstr_lock(self.session)
       
    39 
       
    40 def _acquire_unique_cstr_lock(session):
       
    41     """acquire the _UNIQUE_CONSTRAINTS_LOCK for the session.
       
    42 
       
    43     This lock used to avoid potential integrity pb when checking
       
    44     RQLUniqueConstraint in two different transactions, as explained in
       
    45     http://intranet.logilab.fr/jpl/ticket/36564
       
    46     """
       
    47     global _UNIQUE_CONSTRAINTS_HOLDER
       
    48     asession = session.actual_session()
       
    49     if _UNIQUE_CONSTRAINTS_HOLDER is asession:
       
    50         return
       
    51     _UNIQUE_CONSTRAINTS_LOCK.acquire()
       
    52     _UNIQUE_CONSTRAINTS_HOLDER = asession
       
    53     # register operation responsible to release the lock on commit/rollback
       
    54     _ReleaseUniqueConstraintsHook(asession)
       
    55 
       
    56 def _release_unique_cstr_lock(session):
       
    57     global _UNIQUE_CONSTRAINTS_HOLDER
       
    58     if _UNIQUE_CONSTRAINTS_HOLDER is session:
       
    59         _UNIQUE_CONSTRAINTS_HOLDER = None
       
    60         _UNIQUE_CONSTRAINTS_LOCK.release()
       
    61     else:
       
    62         assert _UNIQUE_CONSTRAINTS_HOLDER is None
    27 
    63 
    28 
    64 
    29 def relation_deleted(session, eidfrom, rtype, eidto):
    65 def relation_deleted(session, eidfrom, rtype, eidto):
    30     session.transaction_data.setdefault('pendingrelations', []).append(
    66     session.transaction_data.setdefault('pendingrelations', []).append(
    31         (eidfrom, rtype, eidto))
    67         (eidfrom, rtype, eidto))
   214         if eidfrom in pending:
   250         if eidfrom in pending:
   215             return
   251             return
   216         if eidto in pending:
   252         if eidto in pending:
   217             return
   253             return
   218         for constraint in self.constraints:
   254         for constraint in self.constraints:
       
   255             # XXX
       
   256             # * lock RQLConstraint as well?
       
   257             # * use a constraint id to use per constraint lock and avoid
       
   258             #   unnecessary commit serialization ?
       
   259             if isinstance(constraint, RQLUniqueConstraint):
       
   260                 _acquire_unique_cstr_lock(self.session)
   219             try:
   261             try:
   220                 constraint.repo_check(self.session, eidfrom, rtype, eidto)
   262                 constraint.repo_check(self.session, eidfrom, rtype, eidto)
   221             except NotImplementedError:
   263             except NotImplementedError:
   222                 self.critical('can\'t check constraint %s, not supported',
   264                 self.critical('can\'t check constraint %s, not supported',
   223                               constraint)
   265                               constraint)