server/repository.py
changeset 10368 1691be295517
parent 10365 21461f80f348
child 10446 1e6655cff5ab
equal deleted inserted replaced
10367:8fc24ce5317e 10368:1691be295517
    25   point to a cubicweb instance.
    25   point to a cubicweb instance.
    26 * handles session management
    26 * handles session management
    27 """
    27 """
    28 __docformat__ = "restructuredtext en"
    28 __docformat__ = "restructuredtext en"
    29 
    29 
    30 import sys
       
    31 import threading
    30 import threading
    32 import Queue
    31 import Queue
    33 from warnings import warn
    32 from warnings import warn
    34 from itertools import chain
    33 from itertools import chain
    35 from time import time, localtime, strftime
    34 from time import time, localtime, strftime
    36 from contextlib import contextmanager
    35 from contextlib import contextmanager
    37 from warnings import warn
       
    38 
    36 
    39 from logilab.common.decorators import cached, clear_cache
    37 from logilab.common.decorators import cached, clear_cache
    40 from logilab.common.deprecation import deprecated
    38 from logilab.common.deprecation import deprecated
    41 
    39 
    42 from yams import BadSchemaDefinition
    40 from yams import BadSchemaDefinition
    43 from rql import RQLSyntaxError
       
    44 from rql.utils import rqlvar_maker
    41 from rql.utils import rqlvar_maker
    45 
    42 
    46 from cubicweb import (CW_MIGRATION_MAP, QueryError,
    43 from cubicweb import (CW_MIGRATION_MAP, QueryError,
    47                       UnknownEid, AuthenticationError, ExecutionError,
    44                       UnknownEid, AuthenticationError, ExecutionError,
    48                       BadConnectionId, Unauthorized, ValidationError,
    45                       BadConnectionId, ValidationError,
    49                       UniqueTogetherError, onevent)
    46                       UniqueTogetherError, onevent)
    50 from cubicweb import cwvreg, schema, server
    47 from cubicweb import cwvreg, schema, server
    51 from cubicweb.server import ShuttingDown, utils, hook, querier, sources
    48 from cubicweb.server import ShuttingDown, utils, hook, querier, sources
    52 from cubicweb.server.session import Session, InternalManager
    49 from cubicweb.server.session import Session, InternalManager
    53 from cubicweb.server.ssplanner import EditedEntity
       
    54 
    50 
    55 NO_CACHE_RELATIONS = set( [('owned_by', 'object'),
    51 NO_CACHE_RELATIONS = set( [('owned_by', 'object'),
    56                            ('created_by', 'object'),
    52                            ('created_by', 'object'),
    57                            ('cw_source', 'object'),
    53                            ('cw_source', 'object'),
    58                            ])
    54                            ])
    59 
    55 
    60 def prefill_entity_caches(entity):
    56 def prefill_entity_caches(entity):
    61     session = entity._cw
    57     cnx = entity._cw
    62     # prefill entity relation caches
    58     # prefill entity relation caches
    63     for rschema in entity.e_schema.subject_relations():
    59     for rschema in entity.e_schema.subject_relations():
    64         rtype = str(rschema)
    60         rtype = str(rschema)
    65         if rtype in schema.VIRTUAL_RTYPES or (rtype, 'subject') in NO_CACHE_RELATIONS:
    61         if rtype in schema.VIRTUAL_RTYPES or (rtype, 'subject') in NO_CACHE_RELATIONS:
    66             continue
    62             continue
    67         if rschema.final:
    63         if rschema.final:
    68             entity.cw_attr_cache.setdefault(rtype, None)
    64             entity.cw_attr_cache.setdefault(rtype, None)
    69         else:
    65         else:
    70             entity.cw_set_relation_cache(rtype, 'subject',
    66             entity.cw_set_relation_cache(rtype, 'subject',
    71                                          session.empty_rset())
    67                                          cnx.empty_rset())
    72     for rschema in entity.e_schema.object_relations():
    68     for rschema in entity.e_schema.object_relations():
    73         rtype = str(rschema)
    69         rtype = str(rschema)
    74         if rtype in schema.VIRTUAL_RTYPES or (rtype, 'object') in NO_CACHE_RELATIONS:
    70         if rtype in schema.VIRTUAL_RTYPES or (rtype, 'object') in NO_CACHE_RELATIONS:
    75             continue
    71             continue
    76         entity.cw_set_relation_cache(rtype, 'object', session.empty_rset())
    72         entity.cw_set_relation_cache(rtype, 'object', cnx.empty_rset())
    77 
    73 
    78 def del_existing_rel_if_needed(session, eidfrom, rtype, eidto):
    74 def del_existing_rel_if_needed(cnx, eidfrom, rtype, eidto):
    79     """delete existing relation when adding a new one if card is 1 or ?
    75     """delete existing relation when adding a new one if card is 1 or ?
    80 
    76 
    81     have to be done once the new relation has been inserted to avoid having
    77     have to be done once the new relation has been inserted to avoid having
    82     an entity without a relation for some time
    78     an entity without a relation for some time
    83 
    79 
    84     this kind of behaviour has to be done in the repository so we don't have
    80     this kind of behaviour has to be done in the repository so we don't have
    85     hooks order hazardness
    81     hooks order hazardness
    86     """
    82     """
    87     # skip that if integrity explicitly disabled
    83     # skip that if integrity explicitly disabled
    88     if not session.is_hook_category_activated('activeintegrity'):
    84     if not cnx.is_hook_category_activated('activeintegrity'):
    89         return
    85         return
    90     rdef = session.rtype_eids_rdef(rtype, eidfrom, eidto)
    86     rdef = cnx.rtype_eids_rdef(rtype, eidfrom, eidto)
    91     card = rdef.cardinality
    87     card = rdef.cardinality
    92     # one may be tented to check for neweids but this may cause more than one
    88     # one may be tented to check for neweids but this may cause more than one
    93     # relation even with '1?'  cardinality if thoses relations are added in the
    89     # relation even with '1?'  cardinality if thoses relations are added in the
    94     # same transaction where the entity is being created. This never occurs from
    90     # same transaction where the entity is being created. This never occurs from
    95     # the web interface but may occurs during test or dbapi connection (though
    91     # the web interface but may occurs during test or dbapi connection (though
    99     # notes:
    95     # notes:
   100     # * inlined relations will be implicitly deleted for the subject entity
    96     # * inlined relations will be implicitly deleted for the subject entity
   101     # * we don't want read permissions to be applied but we want delete
    97     # * we don't want read permissions to be applied but we want delete
   102     #   permission to be checked
    98     #   permission to be checked
   103     if card[0] in '1?':
    99     if card[0] in '1?':
   104         with session.security_enabled(read=False):
   100         with cnx.security_enabled(read=False):
   105             session.execute('DELETE X %s Y WHERE X eid %%(x)s, '
   101             cnx.execute('DELETE X %s Y WHERE X eid %%(x)s, '
   106                             'NOT Y eid %%(y)s' % rtype,
   102                         'NOT Y eid %%(y)s' % rtype,
   107                                 {'x': eidfrom, 'y': eidto})
   103                         {'x': eidfrom, 'y': eidto})
   108     if card[1] in '1?':
   104     if card[1] in '1?':
   109         with session.security_enabled(read=False):
   105         with cnx.security_enabled(read=False):
   110             session.execute('DELETE X %s Y WHERE Y eid %%(y)s, '
   106             cnx.execute('DELETE X %s Y WHERE Y eid %%(y)s, '
   111                             'NOT X eid %%(x)s' % rtype,
   107                         'NOT X eid %%(x)s' % rtype,
   112                             {'x': eidfrom, 'y': eidto})
   108                         {'x': eidfrom, 'y': eidto})
   113 
   109 
   114 
   110 
   115 def preprocess_inlined_relations(session, entity):
   111 def preprocess_inlined_relations(cnx, entity):
   116     """when an entity is added, check if it has some inlined relation which
   112     """when an entity is added, check if it has some inlined relation which
   117     requires to be extrated for proper call hooks
   113     requires to be extrated for proper call hooks
   118     """
   114     """
   119     relations = []
   115     relations = []
   120     activeintegrity = session.is_hook_category_activated('activeintegrity')
   116     activeintegrity = cnx.is_hook_category_activated('activeintegrity')
   121     eschema = entity.e_schema
   117     eschema = entity.e_schema
   122     for attr in entity.cw_edited:
   118     for attr in entity.cw_edited:
   123         rschema = eschema.subjrels[attr]
   119         rschema = eschema.subjrels[attr]
   124         if not rschema.final: # inlined relation
   120         if not rschema.final: # inlined relation
   125             value = entity.cw_edited[attr]
   121             value = entity.cw_edited[attr]
   126             relations.append((attr, value))
   122             relations.append((attr, value))
   127             session.update_rel_cache_add(entity.eid, attr, value)
   123             cnx.update_rel_cache_add(entity.eid, attr, value)
   128             rdef = session.rtype_eids_rdef(attr, entity.eid, value)
   124             rdef = cnx.rtype_eids_rdef(attr, entity.eid, value)
   129             if rdef.cardinality[1] in '1?' and activeintegrity:
   125             if rdef.cardinality[1] in '1?' and activeintegrity:
   130                 with session.security_enabled(read=False):
   126                 with cnx.security_enabled(read=False):
   131                     session.execute('DELETE X %s Y WHERE Y eid %%(y)s' % attr,
   127                     cnx.execute('DELETE X %s Y WHERE Y eid %%(y)s' % attr,
   132                                     {'x': entity.eid, 'y': value})
   128                                     {'x': entity.eid, 'y': value})
   133     return relations
   129     return relations
   134 
   130 
   135 
   131 
   136 class NullEventBus(object):
   132 class NullEventBus(object):
   764 
   760 
   765     def type_from_eid(self, eid, cnx):
   761     def type_from_eid(self, eid, cnx):
   766         """return the type of the entity with id <eid>"""
   762         """return the type of the entity with id <eid>"""
   767         return self.type_and_source_from_eid(eid, cnx)[0]
   763         return self.type_and_source_from_eid(eid, cnx)[0]
   768 
   764 
   769     def querier_cache_key(self, session, rql, args, eidkeys):
   765     def querier_cache_key(self, cnx, rql, args, eidkeys):
   770         cachekey = [rql]
   766         cachekey = [rql]
   771         for key in sorted(eidkeys):
   767         for key in sorted(eidkeys):
   772             try:
   768             try:
   773                 etype = self.type_from_eid(args[key], session)
   769                 etype = self.type_from_eid(args[key], cnx)
   774             except KeyError:
   770             except KeyError:
   775                 raise QueryError('bad cache key %s (no value)' % key)
   771                 raise QueryError('bad cache key %s (no value)' % key)
   776             except TypeError:
   772             except TypeError:
   777                 raise QueryError('bad cache key %s (value: %r)' % (
   773                 raise QueryError('bad cache key %s (value: %r)' % (
   778                     key, args[key]))
   774                     key, args[key]))